0

I'm trying to do a deep dive into the linux source code and I'm seeing the following pattern of embedding a struct list_head to form a doubly linked list, this is on skbuff.h

struct sk_buff {
    union {
        struct {
            /* These two members must be first to match sk_buff_head. */
            struct sk_buff      *next;
            struct sk_buff      *prev;
        };
    
        ...
        struct list_head    list; <- list_head as above mentioned
    };

    ...
}

So, basically, whenever you want access some member of the list you need some pointer to list_head, move it however you want and when you are in the position you need use this convenient macro defined on include/linux/container_of.h to get an outer reference (a reference to sk_buff-><some member> for example)

#define container_of(ptr, type, member) ({                      \
    void *__mptr = (void *)(ptr);                               \
    static_assert(__same_type(*(ptr), ((type *)0)->member) ||   \
                  __same_type(*(ptr), void),                    \
                  "pointer type mismatch in container_of()");   \
    ((type *)(__mptr - offsetof(type, member))); })

But I'm having trouble at understanding what container_of macro do, especially what ((type *)0)->member) means (I never saw that kind of pointer to 0) and why ((type *)(__mptr - offsetof(type, member)) works (I believe my concern here is how to use it in the context of mantaining the linked list and not just accesing a member of a given struct).

Could someone please help explaining the above two points about container_of macro ?, I'm not a noob on C but I never saw those patterns before and I was unable to get some interesting results on Google.

Really thanks, cheers.

ca-hercor
  • 1
  • 1
  • 1
    I think the idea is that you have a pointer to a member of a structure, and from that pointer you want to obtain the address of the structure itself. For example, if you have `struct foo {int a; int b;}` and you have a pointer to the `b` field of an instance of that structure, you can use the macro to obtain the address of the structure itself. – Tom Karzes Oct 14 '22 at 19:49
  • `((type *)0)->member)`: `(type *)` is a cast to pointer to type. 0 is an object that allows that cast. Now that you have pointer to the type, it tries to access the struct pointer's `member`. It's part of a static_assert that can checks if it's possible and otherwise generates an error message. – Allan Wind Oct 14 '22 at 19:51

0 Answers0