一直很是疑惑container_of是什么意思,最近看了一些资料,整理一下。
1)typeof
首先,我们要知道typeof,它是gcc的C语言扩展保留字,用于声明变量类型。typeof的参数可以是两种形式:表达式或类型。例如:
typeof(x)
这里假设x是一个函数指针,这样就可以得到这个函数返回值的类型了。
如果将typeof用于表达式,则该表达式不会执行。只会得到该表达式的类型。以下示例声明了int类型的var变量,因为表达式foo()是int类型的。由于表达式不会被执行,所以不会调用foo函数。
extern int foo();
typeof(foo()) var;
下面是用类型作参数的例子:
typeof(int *) a,b;
等价于:
int *a,*b;
下面是两个等效声明,用于声明int类型的变量a。
typeof(int) a; /*int类型*/
typeof('b') a; /* GCC中这个表达式的类型是int(自动提升为int),注意typeof(char)和typeof('b')得到的不是一样的,这个用sizeof可以看出来*/
一般情况下用typeof就可以了,但是如果要于ISO C兼容的话,最好是用双下划线的形式:__typeof__。
typeof和typedef很像,事实上,只要能用typedef的地方就可以用typeof。
把y定义成一个字符指针数组:
typeof(typeof(char *))[4] y;
这与下面的定义等价:
char *y[4];
在宏声明中使用typeof
typeof构造的主要应用是用在宏定义中。可以使用typeof关键字来引用宏参数的类型。因此,在没有将类型名明确指定为宏实参的情况下,构造带有所需类型的对象是可能的。
下面是一个交换两个变量的值的宏定义:
#define SWAP(a,b) {\
typeof(a) _t=a;\
a=b;\
b=_t;}
这个宏可以交换所有基本数据类型的变量(整数,字符,结构等)
原文参考:http://blog.csdn.net/wslong/article/details/7728811
2)#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
获取TYPE类型中成员MEMBER的相对偏移量,如果基址为0,那么地址&((TYPE *)0)->MEMBER转换为size_t后就是此成员的偏移量了。这里的0作为起始地址用,来计算偏移量,如果用其它数字代替offsetof得到的数值要减去这个数字才是真正的偏移量,所以这里用0是最佳的选择。
3)const typeof( ((type *)0)->member ) *__mptr = (ptr);
定义一个__mptr指针变量,类型和member的类型一样
typeof是获得一个变量的类型,((type *)0)->member 则是tpye类型中的member 变量,一般type为结构体类型,member 则为其中的变量。
4)#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
(type *)( (char *)__mptr - offsetof(type,member) );意思是__mptr的地址减去member在该struct中的偏移量得到的地址, 再转换成type型指针. 该指针就是member的入口地址了.
也就是说,container_of是通过ptr获取到了type成员member的入口地址,然后再获得type结构的地址。
container_fo举例:
struct demo_struct {
type1 member1;
type2 member2;
type3 member3;
type4 member4;
};
struct demo_struct demo;
同时,如果在另一个地方,获得了变量demo中的某一个域成员变量的指针,比如:
type3 *memp = get_member_pointer_from_somewhere();
此时,如果需要获取指向整个结构体变量的指针,而不仅仅只是其某一个域成员变量的指针,我们就可以这么做:
struct demo_struct *demop = container_of(memp, struct demo_struct, member3);