Comment by glouwbug
12 hours ago
Combined with C23's auto (see vec_for) you can technically backport the entirety of C++'s STL (of course with skeeto's limitation in his last paragraph in mind). gcc -std=c23. It is a _very_ useful feature for even the mundane, like resizable arrays:
#include <stdlib.h>
#include <stdio.h>
#define vec(T) struct { T* val; int size; int cap; }
#define vec_push(self, x) { \
if((self).size == (self).cap) { \
(self).cap = (self).cap == 0 ? 1 : 2 * (self).cap; \
(self).val = realloc((self).val, sizeof(*(self).val) * (self).cap); \
} \
(self).val[(self).size++] = x; \
}
#define vec_for(self, at, ...) \
for(int i = 0; i < (self).size; i++) { \
auto at = &(self).val[i]; \
__VA_ARGS__ \
}
typedef vec(char) string;
void string_push(string* self, char* chars)
{
if(self->size > 0)
{
self->size -= 1;
}
while(*chars)
{
vec_push(*self, *chars++);
}
vec_push(*self, '\0');
}
int main()
{
vec(int) a = {};
vec_push(a, 1);
vec_push(a, 2);
vec_push(a, 3);
vec_for(a, at, {
printf("%d\n", *at);
});
vec(double) b = {};
vec_push(b, 1.0);
vec_push(b, 2.0);
vec_push(b, 3.0);
vec_for(b, at, {
printf("%f\n", *at);
});
string c = {};
string_push(&c, "this is a test");
string_push(&c, " ");
string_push(&c, "for c23");
printf("%s\n", c.val);
}
What I don't quite get is why they didn't go all the way in and basically enabled full fledged structural typing for anonymous structs.
That way my plan, but the committee had concerns about type safety.
This would probably need some special rules around stuff like:
i.e. these are meant to be named types and thus should remain nominal even though it's technically a typedef. And ditto for similarly defined pointer types etc. But this is a pattern regular enough that it can just be special-cased while still allowing proper structural typing for cases where that's obviously what is intended (i.e. basically everywhere else).