这两个是在linux内核中经常用到的两个宏,先说offsetof这个宏的作用就是来计算在结构体中的一个元素与结构体地址的偏移量。结构体的元素访问其实就是指针访问,直接应用的时候是用一个点来访问的但是其实在底层经过编译器编译后的执行程序还是用这个偏移量的地址来访问的例如定义一个结构体如下
typedef struct test{
char t1;
int t2;
short t3;
}test;
int main(void)
{
test s1;
s1.t1='a';
s1.t2=123;
s1.t3=456;
return 0;
}
这种用点的形式直接访问其本质是如下的:
test p;
char p1;
int p2;
short p3;
p=&s1;
p1=(char )((int)p+0)
p2=(int)((int)p + 4);
p3=(short *)((int)p + 8);
printf("*p1 = %c.\n",*p1);
printf("*p2 = %d.\n",*p2);
printf("*p3 = %d.\n",*p3);
这样得到结构是完全正确的意思就是这个偏移量很重要,所有就产生了offsetof这个宏,他的原型是
#define offsetof(Type,Member) ((int)&((Type*)0)->Member)
首先有两个参数Type是指这个结构体的类型名,member就是这个结构体的成员名经过这个宏之后就返回了一个×××数是这个成员变量在这个结构体中相对于结构体地址的偏移量这里边有一个(Type*)0)最不好理解意思就是假设了一个type类型的结构体他的地址是在地址0处其实这个结构体是不存在的但是这样假定使用是不会有问题的,因你又没有引用这个地址所有就没有问题了,其实返回的这个数就是这个成员的地址减去结构体的地址但是因为结构体的地址是0所有就能直接返回这个成员的地址而也正因为结构体的地址是零所有成员的地址也就正好是偏移量了。
而container_of这个宏就是在offsetof这个宏的基础上发展来的他的作用就是知道一个结构体中的成员的地址通过这个宏的运算后得到了结构体的地址,这个就厉害了因为你只要知道了结构体的指针那么你就可以得到结构体中的任何一个元素。这个宏的源型是#define container_of(ptr,type,member) ({\
Const typeof(((type)0)->member) mptr = (ptr);\
(type)((char)mptr - offsetof(type,member));})
有三个参数ptr是结构体中元素的指针,type是结构体的类型名,member是这个ptr指针的结构体元素名。这个宏里第一条我觉得其实也没什么用去掉应该也可以因为他只是得到了这个结构体中成员变量的类型,之后这个成员变量的地址减去他在结构体中的偏移量那得到的就是结构体的指针在将类型强制转换为结构体指针就可以了。
转载于:https://blog.51cto.com/13638458/2339375