Self referential C99 initializers

Viewed 112

Consider:

struct N {
  struct N *next, *prev;
};

struct X {
  struct N *first, *last;
};

int fun()
{
  struct X tmp = {
    .first = &(struct N) {.next = ???},
    .last  = &(struct N) {.prev = ???},
  };

  return 0;
}

void main()
{
  fun();
}

I come across situations, like the above, where it would be really useful to be able to get a pointer to the structure I'm initializing as part of the initialization process. Something like "this" in C++. I realize I can use the name of the variable, but that precludes doing something like:

struct X x = MAGIC_INITIALIZER_MACRO;

Is there a way to do this?

And as long as I'm on the subject of initialization, if the order of the initialization statements doesn't match the order they are declared in the structure, which order does the compiler use?

1 Answers

What about:

struct X createX(struct N *n) {
    n->next = n->prev = n;
    return (struct X) { .first = n, .last = n };
}

#define MAGIC_INITIALIZER_MACRO createX(&(struct N){0})

int main() {
  struct X x = MAGIC_INITIALIZER_MACRO;

  #define DBG(V) printf(#V " = %p\n", (void*)(V));
  DBG(x.first);
  DBG(x.last);
  DBG(x.first->next);
  DBG(x.first->prev);

  return 0;
}

On my machine it produced the expected output:

x.first = 0x7fff22f32ab0
x.last = 0x7fff22f32ab0
x.first->next = 0x7fff22f32ab0
x.first->prev = 0x7fff22f32ab0

Lifetime of the compound literal inside the macro is the same as x.

Related