sexta-feira, 11 de novembro de 2011

container_of

/*
 * This example show how get sibling members of a struct. Suppose that you
 * have a struct foo with members A and B. With the macros provided here you can
 * get the address of B, having a pointer to A and knowing that B is the B member
 * of struct foo. This is not my work, is just based on macros provided by gcc
 * compiler __builtin_offsetof() and the container_of() macro found on linux
 * kernel sources. 
 */ 
#include <stdio.h> 

/*
 * You can get the offset of a member on a struct by dereferencing that member on
 * address 0 of such structure.
 */
#define offset_of(type, member) ((unsigned long) &((type *)0)->member)

/*
 * With the capability to get offsets, is possible to get the address of the
 * struct that contains some data. We just need a pointer to that data and the
 * offset of that data on the struct. With this informations we can calculate
 * the address of struct by subtracting the offset from the pointer to that data
 * contained on struct. In the macro above the @ptr is the data contained on
 * struct.
 */
#define container_of(ptr, type, member) \
        ((type *) ((char *)ptr - offset_of(type, member)))

struct foo {
        char *str;
        int len;
};

void print_sibling(int *ip);

int main(void)
{
        struct foo bar = {
                .str = "Hello World",
                .len= 11,
        }; 
        print_sibling(&bar.len);
        
        return 0;

}

/*
 * This function receives an int pointer (@ip) that is known to be the member "len" of
 * a "struct foo". With such information we can do the magic and take any
 * "sibling" member of that struct.
 */
void print_sibling(int *ip)
{
        struct foo *tmp = container_of(ip, struct foo, len);
        puts(tmp->str);
}


Nenhum comentário:

Postar um comentário