Self-referential variable initialization in C

(microblog.ahti.space)

3 points | by todsacerdoti 12 hours ago ago

2 comments

  • fanf2 9 hours ago 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 11 hours ago ago

    This is also useful initializing empty circular linked lists

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