Sunday 15 April 2012

Using offsetof to implement linked lists

offsetof is a cute litte feature in C. What the function gives is the offset that a member has in a struct. Assume we have the given struct:

typedef struct {
   int a;
   char c;
   int b;
} s;
Offsetof would return something like this on fairly normal hardware:


offsetof(s, a); /*0 */
offsetof(s, c); /*4 */
offsetof(s, b); /*8 - no, not 5, more about that later... */
So what can this be used for? Well, a quite common use is for linked lists. A doublylinked list will often be written with two structures:



typedef struct link_t {
    struct link *next_link;
    struct link *prev_link;
} link;

typedef struct list_t {
    struct link *first_link;
    struct link *last_link;
}
Then, any structure that wants to be in a link list adds the link structure as a member:


typedef struct interesting_data {
    link_t link;
    int data;
} interesting_data;
To insert into a linked list, we then use a macro.



#define LIST_INSERT_BACK(list, link, member)\
do {\
    char *p = (char*)link;\
    link_t *l = (link_t*)((char*)link) + offsetof(typeof(link), member));\
    private_insert_back_link(list, l);\
}\ while(0)

#define LIST_GET_BACK(list, link_type, member)\
\ (link_type*) private_get_back_link(list, offsetof(link_type, member));


There are of course quite a few macros needed (to traverse the list, etc.), but they are all based on using offsetof to find the offset of the list member.

No comments:

Post a Comment