0

Is there a portable way to get a pointer to a structure if you have a pointer to a member of that structure?

There is a linked list implementation in Linux kernel (1):

struct list_head {
    struct list_head *next, *prev;
};

static inline void __list_add(struct list_head *new,
                  struct list_head *prev,
                  struct list_head *next)
{
    next->prev = new;
    new->next = next;
    new->prev = prev;
    prev->next = new;
}

static inline void list_add(struct list_head *new, struct list_head *head)
{
     __list_add(new, head, head->next);
}

#define list_entry(ptr, type, member) \
    container_of(ptr, type, member)

The idea is that this implementation is generic. You can use it with any struct type:

struct my_struct {
    int my_data;

    struct list_head node;
};

void example()
{
    struct list_head head;
    struct my_struct element1 = { 1 };
    struct my_struct element2 = { 2 };

    head.next = head.prev = &head;   // head <-> head
    list_add(&element1.node, &head); // head <-> {1} <-> head
    list_add(&element2.node, &head); // head <-> {2} <-> {1} <-> head

    struct my_struct *front_element = list_entry(&head.next, struct my_struct, node);

    printf("front element data: %d\n", front_element->my_data); // will print "2"
}

Elements of list_head are linked with each other, but there are only pointers to list_head and there are no pointers to my_struct (that contains list_head inside). However having a pointer to the node member of my_struct, you can convert this pointer to a pointer to my_struct itself using the list_entry macro. This is done using tricky pointer arithmetic (the offset of the member in the struct is subtracted from the address of the member).

But the implementation of the container_of macro is not portable because it uses gcc extensions and deferencing of null pointer (which is generally UB):

#define container_of(ptr, type, member) ({          \
    const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
    (type *)( (char *)__mptr - offsetof(type,member) );})

Is there a way to make a portable implementation of this macro?

anton_rh
  • 8,226
  • 7
  • 45
  • 73
  • Sorry, if this is a dup. I really couldn't find a similar question. – anton_rh May 30 '18 at 15:19
  • The only workaround I can think of is to add `void* ptr` to `list_head` and set it to pointer to `my_struct` in each node. But there is a small waste of resources in this case (each node contains an additional pointer, and each node requires additional initialization). – anton_rh May 30 '18 at 15:28
  • 1
    Is [this](https://stackoverflow.com/questions/10269685/kernels-container-of-any-way-to-make-it-iso-conforming) what you're looking for? – Robert Derber May 30 '18 at 16:26
  • @RobertDerber, oh yeah. Exactly. Thank you! It seems that my google-fu is still bad -_- – anton_rh May 31 '18 at 04:38
  • 1
    BTW, the linked list implementation that uses `container_of`: https://stackoverflow.com/a/50619249/5447906 – anton_rh May 31 '18 at 07:50

0 Answers0