offsetof

From Seo Wiki - Search Engine Optimization and Programming Languages

Jump to: navigation, search

C's offsetof() macro is an ANSI C library feature found in stddef.h. It evaluates to the offset (in bytes) of a given member within a struct or union type, an expression of type size_t.

The offsetof() macro takes two parameters, the first being a structure name, and the second being the name of a member within the structure.

Implementation

A typical implementation of the macro will rely on the compiler being able to optimize the combination of the member-by-pointer operator -> and the dereference operator & into addition, thereby obtaining the offset of the member by specifying a hypothetical structure that begins at 0:

#define offsetof(st, m) \
    ((size_t) ( (char *)&((st *)(0))->m - (char *)0 ))

This works by casting a null pointer into a pointer to structure st, obtaining the address of member m within this structure, casting that address into a character pointer, then using pointer arithmetic to subtract the base address of the structure, all of which results in the number of character positions (i.e., bytes) between the beginning of the structure and the beginning of the member. The offsets evaluated will differ from compiler to compiler, and with build settings, but the calculations themselves are entirely portable.

Usage

It is useful when implementing generic data structures in C. The following (incomplete) code is a generic implementation of a Doubly-linked list.

#include <stdlib.h>
#include <stdint.h>
#include <stddef.h>
#include <assert.h>
 
struct LinkedListNode
{
    struct LinkedListNode *prev;
    struct LinkedListNode *next;
};
 
struct LinkedList;
{
    struct LinkedListNode *first;
    struct LinkedListNode *last;
    struct LinkedListNode *it_next;
};
 
void LinkedList_Init (struct LinkedList *list)
{
    list->first = NULL;
    list->last = NULL;
    list->it_next = NULL;
}
 
void LinkedList_Append (struct LinkedList *list, struct LinkedListNode *node)
{
    node->prev = list->last;
    node->next = NULL;
    if (list->last) {
        list->last->next = node;
    } else {
        list->first = node;
    }
    list->last = node;
}
 
void LinkedList_Remove (struct LinkedList *list, struct LinkedListNode *node)
{
    if (node->prev)
        node->prev->next = node->next;
    else
        list->first = node->next;
 
    if (node->next)
        node->next->prev = node->prev;
    else
        list->last = node->prev;
 
    if (node == list->it_next)
        list->it_next = node->next;
}
 
void LinkedList_GoToStart (struct LinkedList *list)
{
    list->it_next = list->first;
}
 
struct LinkedListNode * LinkedList_Next (struct LinkedList *list)
{
    struct LinkedListNode *next = list->it_next;
    if (next)
        list->it_next = next->next;
    return next;
}

The above data structure does not contain any real data. We can use it by embedding the LinkedListNode structure into a structure of our own. When we iterate, we are only given pointers to LinkedListNode structures. We use offsetof() to obtain pointers to our structures from these:

struct my_entry
{
    int num;
    struct LinkedListNode list_node;
};
 
int main (void)
{
    /* create empty list */
    struct LinkedList list;
    LinkedList_Init(&list);
 
    /* add entries to list */
    int i;
    for (i = 0; i < 10; i++)
    {
        struct my_entry  *entry;
        entry = malloc(sizeof(*entry));
        if (entry == NULL)
            continue;
        entry->num = i;
        LinkedList_Append(&list, &entry->list_node);
    }
 
    /* print and remove entries */
    LinkedList_GoToStart(&list);
    struct LinkedListNode *node;
    while ((node = LinkedList_Next(&list)) != NULL)
    {
        /* use offsetof() to obtain the pointer to the parent my_entry structure */
        struct my_entry  *entry;
        entry = (struct my_entry *)((uint8_t *)node - offsetof(struct my_entry, list_node));
        printf("Number: %d\n", entry->num);
 
        /* remove entry from list and free it */
        LinkedList_Remove(&list, &entry->list_node);
        free(entry);
    }
 
    return 0;
}

Resources

MSDN offsetof reference

GCC offsetof referencept:Offsetof

Personal tools

Served in 0.076 secs.