1. Linux内核中常用的两个宏定义
(1)offsetof宏:用于计算TYPE结构体中MEMBER成员的偏移位置
#ifndef offsetof #define offsetof(TYPE, MEMBER) ((size_t)&((TYPE*)0)->MEMBER) #endif
(2)container_of宏:根据成员变量指针反推结构体对象的起始地址
//const typeof(...):编译期类型检查,const指针兼容const和非const指针类型 #ifndef container_of #define container_of(ptr, type, member) ({ const typeof(((type*)0)->member)* __mptr = (ptr); (type*)((char*)__mptr - offsetof(type, member));}) #endif
2. 原理剖析
(1)巧用0地址
①编译器清楚的知道结构体成员变量的偏移地址
②通过结构体变量首地址与偏移量定位成员变量
【编程实验】offsetof宏
//offsetof.c
#include "stdio.h" #ifndef offsetof #define offsetof(TYPE, MEMBER) ((size_t)&((TYPE*)0)->MEMBER) #endif struct ST { int i; //offset 0 int j; //offset 4 char c; //offset 8 }; void func(struct ST* pst) { int* pi = &(pst->i); //(unsigned int)pst + 0; int* pj = &(pst->j); //(unsigned int)pst + 4; char* pc = &(pst->c); //(unsigned int)pst + 8; printf("pst = %pn", pst); printf("pi = %pn", pi); printf("pj = %pn", pj); printf("pc = %pn", pc); }; int main() { struct ST s = {0}; func(&s); func(NULL);//借用0地址计算成员变量的偏移地址,相当于pst=0 printf("offset i: %dn", offsetof(struct ST, i)); //0 printf("offset j: %dn", offsetof(struct ST, j)); //4 printf("offset c: %dn", offsetof(struct ST, c)); //8 return 0; } /*输出结果 pst = 0029FEA4 pi = 0029FEA4 pj = 0029FEA8 pc = 0029FEAC pst = 00000000 pi = 00000000 pj = 00000004 pc = 00000008 offset i: 0 offset j: 4 offset c: 8 */
(2)({})是何方神圣
①它是GNU C编译器的语法扩展
②与逗号表达式类似,结果为最后一个语句的值
(3)typeof关键字
①typeof是GNU C编译器的特有关键字
②typeof只在编译期生效,用于得到变量的类型
(4)container_of原理
【编程实验】container_of原理
//container_of.c
#include "stdio.h" #ifndef offsetof #define offsetof(TYPE, MEMBER) ((size_t)&((TYPE*)0)->MEMBER) #endif //const typeof(...):编译期类型检查,const指针兼容const和非const指针类型 #ifndef container_of #define container_of(ptr, type, member) ({ const typeof(((type*)0)->member)* __mptr = (ptr); (type*)((char*)__mptr - offsetof(type, member));}) #endif struct ST { int i; //offset 0 int j; //offset 4 char c; //offset 8 }; //({})是何方神圣 void func() { int a = 0; int b = 0; int c = (a=1, b=2, a+b); //括号表达式 int d = ({int a=1; int b=2; a+b;}); //({})表达式,其中的{}表示一个作用域,{}外再加上()表示取最后一个语句的值 //功能上类似于逗号表达式,这是GNU C扩展语法 printf("c = %dn", c); printf("d = %dn", d); } //typeof关键字:GNU C的扩展关键字 void type_of() { int i = 100; typeof(i) j = i; const typeof(j)* p = &j; printf("sizeof(j)= %dn", sizeof(j)); printf("j = %dn", j); printf("*p = %dn", *p); } int main() { func(); type_of(); struct ST s = {0}; char* pc = &s.c; int e = 0; int* pe = &e; struct ST* pst = container_of(pc, struct ST, c); //struct ST* pst = container_of(pe, struct ST, e); //类型检查,编译不过 printf("&s = %pn", &s); printf("pst = %pn", pst); //pst == &s; return 0; } /*输出结果 c = 3 d = 3 sizeof(j)= 4 j = 100 *p = 100- &s = 0029FE94 pst = 0029FE94 */
3. 小结
(1)编译器清楚地知道结构体成员变量的偏移位置
(2)({})与逗号表达式类似,结果为最后一个语句的值
(3)typeof只在编译期生效,用于得到变量的类型
(4)container_of使用({})进行类型安全检查
原文链接: https://www.cnblogs.com/5iedu/p/7148969.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;
也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/393193
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!