网站开发报价和开发周期,黑龙江做网站的,机械公司网站源码,装饰公司网站开发1、前面说的我在好几年前读linux 驱动代码的时候看到这个宏#xff0c;百度了好久#xff0c;知道怎么用了#xff0c;但是对实现过程和原理还是一知半解。container_of宏 在linux内核代码里面使用次数非常非常多#xff0c;对于喜欢linux编程的同学来说#xff0c;了解其… 1、前面说的我在好几年前读linux 驱动代码的时候看到这个宏百度了好久知道怎么用了但是对实现过程和原理还是一知半解。container_of宏 在linux内核代码里面使用次数非常非常多对于喜欢linux编程的同学来说了解其实现方法对以后看内核代码写内核驱动的帮助都非常大当然我不是说了解这个就可以为所欲为了内核博大精深先宏观再微观去学习不积跬步何以致千里不要想着一口就能吃成一个胖子我这篇文章主要剖析一下这个函数的实现原理希望对大家学习过程中有所帮助。android7.1/kernel/drivers/inputkernel/drivers/input$ grep -rn container_of ./|wc -l710android7.1/kernel/drivers/input$ 使用grep -rn container_of ./|wc -l统计了下kernel/drivers/input/目录下的container_of出现的次数一共有710次使用。2、container_of的作用container_of的作用的通过结构体成员变量地址获取这个结构体的地址假设你的名字叫李光明你还有一个弟弟叫做XXX警察叔叔发现你弟弟XXX干了一件坏事但是警察叔叔不知道你弟弟的名字抓你来审问你嘴巴很硬就是不说警察叔叔就拿到你的名字查到了你家的户口本这下你弟弟就被查出来了原来你弟弟XXX的名字叫做李小明。这种破案手法叫做顺藤摸瓜。内核函数调用常常给函数传入的是结构体成员地址然后在函数里面又想使用这个结构体里面的其他成员变量所以就引发了这样的问题我认为这个也是用C实现面向对象编程的一种方法。比如这段代码static void sensor_suspend(struct early_suspend *h) { struct sensor_private_data *sensor container_of(h, struct sensor_private_data, early_suspend); if (sensor-ops-suspend) sensor-ops-suspend(sensor-client); } early_suspend是sensor_private_data 里面的一个成员通过这个成员的地址获取sensor_private_data结构体变量的地址从而调用里面的成员变量client。这个方法非常优雅。在这里我用到了一个比较叼的词叫“优雅”。这里简单说下传进来的h一定在其他地方定义并且操作系统分配了内存空间h分配了空间说明他的老爸也有内存了要不然你顺藤摸瓜摸到一个NULL就傻逼了。3、如何使用container_ofcontainer_of需要传入三个参数第一个参数是一个指针第二个参数是结构体类型第三个是对应第二个参数里面的结构体里面的成员。container_of(ptr, type, member)ptr:表示结构体中member的地址 htype:表示结构体类型 struct sensor_private_datamember:表示结构体中的成员 early_suspend type里面一定要有这个成员不能瞎搞啊返回结构体的首地址4、container_of 用到的知识点 剖析4.1、({})的作用({})、第一个先说这个表达式很多人可能懂可能在很多地方见到这个表达式但是自己却没有注意这个表达式返回最后一个表达式的值。比如x({a;b;c;d;})最终x的值应该是d。代码例子#includestdio.hvoid main(void){ int a({1;2;4;})10; printf(%d\n,a);//a14}4.2、typeof获取变量的类型这个我们很少看到这个关键字是C语言关键字的拓展返回变量的类型具体可以看GCC里面的介绍https://gcc.gnu.org/onlinedocs/gcc/Typeof.htmlAnother way to refer to the type of an expression is with typeof. The syntax of using of this keyword looks like sizeof, but the construct acts semantically like a type name defined with typedef.代码例子void main(void){ int a 6; typeof(a) b 9; printf(%d %d\n,a,b);}4.3、(struct st*)0的作用尺子大家应该都用过吧比如我想用尺子量一本书本的长度我们第一时间就需要找到尺子的0刻度的位置然后用这个0刻度的位置去对准书本的边然后再贴合对齐在书本的另一边查看尺子刻度就可以知道书本的长度了。现在我们需要量一个结构体的长度我们也可以用尺子来量我们只要找到这个0刻度的位置就可以了。同理即使我们不知道0刻度位置我们首尾刻度相减一样可以计算出结构体的长度。但是在C语言里什么事尺子呢你想到的可能是sizeof不幸的是这个并不能满足我们的需要所以才有了(struct st *),这个当作尺子真的再好不过了。struct st{ int a; int b;}*p_st,n_st;void main(void){ printf(%p\n,((struct st*)0)-b);}上面的代码(struct st*)0这个的意思就是把这个结构体放到0刻度上面开始量了然后量到哪里呢((struct st*)0)-b)这个就体现出来了量到b的位置。所以上面的输出应该是4。看完上面的解释应该知道下面这两个代码的功能是一样的。typeof ((struct st*)0)-b) c; // 取b的类型来声明cint c;其实不只是对于0用其他数字一样是有效的比如下面的代码编译器关心的是类型而不在乎这个数字。printf(%p\n,((struct st*)4)-b -4 );这文章写了有几天了但是一直不想直接发出去因为我觉得这个核心点总是没有找到一个特别好的论证方法看完上面后大概对这种测量应该有点感觉了吧如果现在需要你把一个数组的首地址设置为0要怎么做呢先思考一下假设这里延迟了几分钟。代码如下struct A { short array[100];};int main(int argc, char *argv[]){ int i 10; A* a (A*)0; printf(%p %d %d\n,a,sizeof(short), a-array[20]); getchar(); return 1;}//输出 00000000 2 40有什么办法不使用struct A * 直接把数组的地址放到0位置呢目前我还没有找到其他更好的办法如果有好的建议的请留言给我。4.4、offsetof(TYPE, MEMBER)#define offsetof(TYPE, MEMBER) ((size_t) ((TYPE*)0)-MEMBER)size_t 这个有不懂的可以百度下就是unsigned 的整数在32位和64位下长度不同所以这个offsetof就是获取结构体的偏移长度。4.5、const int* p的作用上面的宏定义里面还有一个小知识点const typeof( ((type *)0)-member ) *__mptr上面的代码可以简写成const int * __mptr这个说明什么问题呢这个说明__mptr指向的整型数据是一个const常数。这就涉及到两外两个知识int * const __mptr;//表示__mptr的值不能改变//和const int * const __mptr; //表示__mptr不能改变而且指向的内容也不能改变5、 container_of 剖析看完上面的几个知识点再来看container_of这个宏就显得非常清晰了。我把解析部分写在下面的代码注释里面。#define offsetof(TYPE, MEMBER) ((size_t) ((TYPE*)0)-MEMBER)#define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)-member ) *__mptr (const typeof( ((type *)0)-member ) *)(ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );})//-----分割线struct st{ int a; int b;}*pt;//用这个来举例container_of(pt-a,struct st,a) const typeof( ((struct st *)0)-a ) *__mptr (const typeof( ((struct st *)0)-a ) *)(pt-a);const int *__mptr (int *)(pt-a);//第一句解析完实际上就是获取a的地址。(type *)( (char *)__mptr - offsetof(type,member) );//这个变成(struct st *)( (char *)__mptr - ((unsigned int) ((struct st*)0)-a));//这句的意思把a的地址减去a对结构体的偏移地址长度那就是结构体的地址位置了。6、实例代码经过上面的解释至少对这个宏有感觉了吧写个代码来测试一下让自己与代码融合为一体这样才能做到人码合一的境界。代码如下#includestdio.h#includestddef.h#includestdlib.h#define offsetof(TYPE, MEMBER) ((size_t) ((TYPE*)0)-MEMBER)/*ptr 成员指针* type 结构体 比如struct Stu* member 成员变量跟指针对应* */#define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)-member ) *__mptr (const typeof( ((type *)0)-member ) *)(ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );})typedef struct Stu{ int age; char name[10]; int id; unsigned long phone_num;}*p_stu,str_stu;void print_all(void *p_str){ p_stu m1p_stu NULL; m1p_stu container_of(p_str,struct Stu,age); printf(age:%d\n,m1p_stu-age); printf(name:%s\n,m1p_stu-name); printf(id:%d\n,m1p_stu-id); printf(phone_num:%d\n,m1p_stu-phone_num);}void main(void){ p_stu m_stu (p_stu)malloc(sizeof(str_stu)); m_stu-age 25; m_stu-id 1; m_stu-name[0]w; m_stu-name[1]e; m_stu-name[2]i; m_stu-name[3]q; m_stu-name[4]i; m_stu-name[5]f; m_stu-name[6]a; m_stu-name[7]\0; m_stu-phone_num13267; /*传结构体成员指针进去*/ print_all(m_stu-age); printf(main end\n); if(m_stu!NULL) free(m_stu);}7、程序输出age:25name:weiqifaid:1phone_num:13267main end当你看到这里的时候说明你已经阅读完上面的内容不管怎样感谢您有心或者无意的关注和支持公众号接入了AI功能随意回复任意消息哦比如笑话天气觉得不错请帮忙转发点好看您的每一次支持我都将铭记于心想获取学习资料请点击状态栏公众号福利按钮