最近在看《Linux内核设计与实现》这本书,感觉写得非常棒,看第6章《内核数据结构》的时候,遇到两个非常牛B的宏,据此简单地设计一个考题,以便分析它们。
【题目】:
根据一个结构体某成员的名称和地址,以及结构体的类型,计算出该结构体对象的首地址。
【例如】:
- struct A
- {
- int x;
- int y;
- int z;
- }
- #define GET_HEADER_ADDR(MEMBER_NAME,MEMBER_ADDR,STRUCT_TYPE) (你来实现)
- void main()
- {
- struct A myTest;
- int *pz = &myTest.z;
- printf("addr is %d",GET_HEADER_ADDR(z,pz,struct A) );
- }
不看下面的答案,你来尝试实现上面这个宏吧。
【答案与分析过程】
Linux内核中,用两个非常巧妙地宏实现了,一个是offsetof宏,另一个是container_of宏,下面讲解一下这两个宏。
1. offsetof宏
【定义】:#define offsetof(TYPE, MEMBER) ((size_t) & ((TYPE *)0)->MEMBER )
【功能】: 获得一个结构体变量成员在此结构体中的偏移量。
【例子】:
- struct A
- {
- int x ;
- int y;
- int z;
- };
- void main()
- {
- printf("the offset of z is %d",offsetof( struct A, z ) );
- }
- // 输出结果为 8
- struct A
- {
- int x ;
- int y;
- int z;
- };
- struct A myTest;
- int *pz = &myTest.z;
- struct A* getHeaderPtr( int *pz )
- {
- return container_of( pz , struct A, z );
- }
【分析】:
(2) 定义__mptr指针ptr为指向该成员变量的指针(即指向ptr所指向的变量处)
(3) (char *)__mptr - offsetof(type,member)) 用该成员变量的实际地址减去该变量在结构体中的偏移,来求出结构体起始地址。
(4) ({ })这个扩展返回程序块中最后一个表达式的值。
本文出自 “对影成三人” 博客,请务必保留此出处http://ticktick.blog.51cto.com/823160/619824