Self-referential variable initialization in C

3 pointsposted 11 hours ago
by todsacerdoti

2 Comments

fanf2

8 hours ago

Here’s an example of a classic real-world self-referential initializer.

In BSD `<sys/queue.h>` there are a bunch of macros for various kinds of linked list.

man: https://man.freebsd.org/cgi/man.cgi?query=STAILQ_HEAD_INIT

src: 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):

    struct stailq_head {
        struct stailq_elem *stqh_first;
        struct stailq_elem **stqh_last;
    }
• 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:

    struct stailq_head head = {
        NULL,
        &head.stqh_first,
    };
There, `head` refers to itself!

To append an element, the `STAILQ_INSERT_TAIL()` macro does basically:

    elem->next = NULL;
    *head.sthq_last = elem;
    head.sthq_last = &elem->next;
So normally the last pointer points into an element; the last pointer points into the head only in an empty list.

sebastianmestre

10 hours ago

This is also useful initializing empty circular linked lists

  node n = {
    .data = NULL,
    .prev = &n,
    .next = &n,
  };