upvote
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);
  }
reply
deleted
reply