根据结构体变量地址反推结构体首地址

本文详细介绍了Linux内核中用于计算结构体首地址的两个宏:offsetof和container_of,并通过实例展示了如何使用这些宏解决实际问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

根据结构体变量地址反推结构体首地址 

     最近在看《Linux内核设计与实现》这本书,感觉写得非常棒,看第6章《内核数据结构》的时候,遇到两个非常牛B的宏,据此简单地设计一个考题,以便分析它们。

    【题目】:

    根据一个结构体某成员的名称和地址,以及结构体的类型,计算出该结构体对象的首地址。

    【例如】:

  
  1. struct A   
  2. {   
  3.     int x;   
  4.     int y;   
  5.     int z;   
  6. }   
  7.    
  8. #define GET_HEADER_ADDR(MEMBER_NAME,MEMBER_ADDR,STRUCT_TYPE) (你来实现)  
  9.    
  10. void main()   
  11. {   
  12.     struct A myTest;   
  13.    
  14.     int *pz = &myTest.z;  
  15.    
  16.     printf("addr is %d",GET_HEADER_ADDR(z,pz,struct A) );   
  17.    
  18. }  
 

    不看下面的答案,你来尝试实现上面这个宏吧。

 


    

【答案与分析过程】

    Linux内核中,用两个非常巧妙地宏实现了,一个是offsetof宏,另一个是container_of宏,下面讲解一下这两个宏。

1.  offsetof宏

【定义】:#define offsetof(TYPE, MEMBER) ((size_t) & ((TYPE *)0)->MEMBER )

【功能】: 获得一个结构体变量成员在此结构体中的偏移量。

【例子】: 

  
  1. struct A 
  2.     int x ; 
  3.     int y; 
  4.     int z; 
  5. }; 
  6.  
  7. void main() 
  8.     printf("the offset of z is %d",offsetof( struct A, z )  ); 
  9.  
  10. // 输出结果为 8 
【分析】:
 
该宏,TYPE为结构体类型,MEMBER 为结构体内的变量名。
 
(TYPE *)0) 是欺骗编译器说有一个指向结构TYPE 的指针,其地址值0 
 
(TYPE *)0)->MEMBER 是要取得结构体TYPE中成员变量MEMBER的地址. 因为基址为0,所以,这时MEMBER的地址当然就是MEMBER在TYPE中的偏移了。
 
2. container_of宏(即实现了题目中的功能
 
【定义】:
 
#define container_of(ptr, type, member)   ({const typeof( ((type *)0)->member ) *__mptr = (ptr); (type *)( (char *)__mptr - offsetof(type,member) );})
 
【功能】:
 
从结构体(type)某成员变量(member)指针(ptr)来求出该结构体(type)的首指针。
 
【例子】:

  
  1. struct A 
  2.     int x ; 
  3.     int y; 
  4.     int z; 
  5. }; 
  6.  
  7. struct A myTest; 
  8.  
  9. int *pz = &myTest.z; 
  10.  
  11. struct A* getHeaderPtr( int *pz ) 
  12.     return container_of( pz , struct A, z ); 

 【分析】:

 (1) typeof( ( (type *)0)->member )为取出member成员的变量类型。

(2) 定义__mptr指针ptr为指向该成员变量的指针(即指向ptr所指向的变量处)

(3) (char *)__mptr - offsetof(type,member)) 用该成员变量的实际地址减去该变量在结构体中的偏移,来求出结构体起始地址。

(4) ({ })这个扩展返回程序块中最后一个表达式的值。

 

本文出自 “对影成三人” 博客,请务必保留此出处http://ticktick.blog.51cto.com/823160/619824


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值