container_of宏的作用太神奇了,本人想去了解它具体是怎样实现的,查阅了很多资料发现讲解的不是通俗易懂,当然一些讲的大体上还是能够理解,下面我将我查阅到的资料重新整理,希望给大家更好的理解container_of宏.
内核中container_of宏的定义:
#define container_of(ptr, type, member) ( { \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) ); } )
((type *)0)->member 我根据我个人的理解解释一下,如果不对的话,请指正:通过以0地址做中转来间接获取该结构体中的成员变量(当然也可以用其他地址),比如如下,我通过编程来打印出来
struct mytest
{
int i;
int j;
float k;
char n;
double m
};
//printf("((struct mytest *)0)->j:%d\n",((struct mytest *)0)->j);//这句话会导致段错误,个人猜测可能是对0地址有写入了,导致的错误?希望有人来帮我解惑.
printf("&((struct mytest *)0)->j :0x%x\n",&((struct mytest *)0)->j); // 打印输出0x4 如果以0地址来存放struct mytest 的话,j的值放在4地址处
printf("&((struct mytest *)1)->j :0x%x\n",&((struct mytest *)1)->j); //0x5
printf("&((struct mytest *)2)->j :0x%x\n",&((struct mytest *)2)->j);//0x6
通过上面打印地址信息可以知道:&((type *)0)->member(即offsetof 宏的展开)是menber以哪个地址为基准来偏移的,
typeof( ((type *)0)->member )网上都说是获取member变量的类型,本人深究不了只好记得它是获取类型就行.
假设type是struct mytest ,member 是 j.那member的类型就是int类型,所以const typeof( ((type *)0)->member ) *__mptr 转换为:const int * __mptr .
const typeof( ((type *)0)->member ) *__mptr = (ptr);就是将__mptr指向ptr的地址.我这里打印出来的地址值:0x804a024
offsetof(type,member)展开就是上面&((struct mytest *)0)->j 打印的值.
(type *)( (char *)__mptr - offsetof(type,member) ); __mptr的地址值 - member以0地址为基准(这里(type *)0,所以以0为基准)的偏移值:即0x804a024 - 0x4 = 0x804a020
我打印struct mytest结构体的首地址出来的值:0x804a020,和container_of打印出来的值是一样的,
以上是个人对container_of宏的理解,如果有错误之处恳请指正.