2

I am currently looking into the use of macros in the C language. To get used to them and to learn I am looking at the queue.h library that allows to create dynamic data structures in C.

You can find the source here: bxr.su/OpenBSD/sys/sys/queue.h

Right now I stumbled upon the following definition:

#define SLIST_ENTRY(type) \
    struct { \
    struct type *slh_next;
    }

If I am not mistaken this creates a struct with a pointer that will point to the next element in the singly-linked list. I just can't figure out, why you have to create the struct. Wouldn't just the pointer be enough?

#define SLIST_ENTRY(type) \
    struct type *slh_next 

I guess if you want to create a doubly-linked list, you would create a struct with next & before pointers. So is this just to be consistent, or does the struct in the SLIST define serve a specific purpose?

PS: how do I format code and links on mobile?

Phero
  • 21
  • 2
  • Why would you write such obfuscated code if you can write in an easy way? – haccks Aug 03 '18 at 09:48
  • A header file is **not** a library, it *might* describe the interface of one. In your case, the BSDs typically have the *kernel* source in the `sys` tree, so it's **very likely** not a library interface you're looking at. –  Aug 03 '18 at 10:02
  • As for the actual usecase, this is done for handling the links in a generic way, but right now, I don't see the need for the wrapping anonymous struct either. –  Aug 03 '18 at 10:08

1 Answers1

1

Maybe it doesn't make much sense when you use it in a single linked list but if you see the definitions of the (double linked) list in the source code then its purpose is more clear because now it has two pointers and you just have to add a single LIST_ENTRY structure to your data structure.

#define LIST_ENTRY(type)                                             \
struct {                                                             \
    struct type *le_next;   /* next element */                       \
    struct type **le_prev;  /* address of previous next element */   \
}

LIST_ENTRY(type) expands to an anonymous struct. Anonymous structs were introduced along with anonymous unions in the C11 standard. When an anonymous struct or an anonymous union is enclosed within another struct or union, the enclosing structure acquires the fields of the enclosed anonymous structure.

Look at this question and the example code:

struct entry { 
    ... 
    LIST_ENTRY(entry) entries; 
    ... 
} *n1, *n2, *np;

In this case, the fields of LIST_ENTRY(entry) become fields of entry. So yeah, it's a generalized type of link just as someone said above. Now a function can get the previous and the next element from this structure like this:

#define LIST_INSERT_AFTER(listelm, elm, field) do {                 \
    if (((elm)->field.le_next = (listelm)->field.le_next) != NULL)  \
        (listelm)->field.le_next->field.le_prev =                   \
            &(elm)->field.le_next;                                  \
    (listelm)->field.le_next = (elm);                               \
    (elm)->field.le_prev = &(listelm)->field.le_next;               \
} while (0)
justinpc
  • 797
  • 6
  • 19
bmann
  • 81
  • 6