For the compiler (or linker if global), it already has to prepare a space for the variable, the address is acquired from layout plan, not from referencing the variable at runtime, so the semantics is analogous to "fill number three in the third box."
It's allowed because it's in the spirit of C: both allowing and prohibiting it is almost equally easy, and it's also sometimes useful, so it's allowed. Now, there is a way [0] to statically check whether self-referential value initialization is well-founded or not but... it's kinda tricky to do and so, again in the C's spirit, such diagnostics is not required.
The most common and idiomatic example that relies on a variable being in scope in its initializer is,
But that isn’t, strictly speaking, self-referential. Here’s one that is…In BSD <sys/queue.h> there are a bunch of macros for various kinds of linked list.
https://man.freebsd.org/cgi/man.cgi?query=STAILQ_HEAD_INIT
https://cgit.freebsd.org/src/tree/sys/sys/queue.h
The STAILQ macros define a singly-linked list where the head is a pair of pointers (simplified slightly):
• a pointer to the first element, which is NULL when the list is empty• a pointer to the NULL pointer that terminates the list
The last pointer allows fast appends, O(1) instead of O(n).
When you initialize the head, the last pointer needs to point to the first pointer. The STAILQ_HEAD_INITIALIZER() macro does basically:
There, head refers to itself!To append an element, the STAILQ_INSERT_TAIL() macro does basically:
So normally the last pointer points into an element; the last pointer points into the head only in an empty list.For the compiler (or linker if global), it already has to prepare a space for the variable, the address is acquired from layout plan, not from referencing the variable at runtime, so the semantics is analogous to "fill number three in the third box."
It's allowed because it's in the spirit of C: both allowing and prohibiting it is almost equally easy, and it's also sometimes useful, so it's allowed. Now, there is a way [0] to statically check whether self-referential value initialization is well-founded or not but... it's kinda tricky to do and so, again in the C's spirit, such diagnostics is not required.
[0] https://www.cl.cam.ac.uk/~jdy22/papers/a-right-to-left-type-...
The traditional use case are circular linked lists or similar data structures.
struct foo { struct foo *next; } x = { .next = &x };