通过成员变量地址获取结构体地址

Linux中有一个宏

  1. #define container_of(ptr,type,member) 实现略  
实现了通过成员变量地址获取结构体地址的功能。

今天我想好好想想这个实现的原理是怎么来的。

先定义一个结构体吧

  1. typedef struct  
  2. {  
  3.     int a;  
  4.     int b;  
  5.     int c;  
  6. }ABC;  
再来设计一个函数用来实现功能

  1. int main(void)  
  2. {  
  3.     ABC abc;  
  4.     printf("abc : %p\n",&(abc));  
  5.     printf("abc.c : %p\n",&(abc.c));  
  6.     return 0;  
  7. }  
main()刚刚好,嘿嘿

输出结果为

  1. abc : 0022FF44  
  2. abc.c : 0022FF4C  
因为成员c的地址比abc高,所以按照数学公式:差 = 成员C地址 - abc地址

如何求得这个差呢?

可以这样,把ABC的一个实例映射到0这个地址,这样成员c的地址就是在0的基础上网上加,进而此时成员c的地址

就是它们的差值

这样

  1. printf("%u\n",&(((ABC*)0)->c));  
不过编译,运行后会crash掉,因为0这个地址被printf检测到是非法地址,所以得这样

  1. printf("%u\n",(size_t)&(((ABC*)0)->c));  
这样,传给printf的参数不是一个地址,而是一个普通的常数

好,那么可以求abc地址了

  1. printf("%p\n",&(abc.c) - (size_t)&(((ABC*)0)->c));  
运行,结果是

  1. abc : 0022FF2C  
和abc的地址不对啊,为什么呢?

因为此处&(abc.c)这一句有问题。指针的加减操作的步长是按照这个指针的类型来定的,此处c是int型,则它 - 8,其实地址是 - 8 * sizeof(int).

你看,0022FF2C是不是比0022FF44少24.就是因为它上面的操作多减了24

所以,得这样

  1. printf("abc : %p\n",(unsigned char*)&(abc.c) - (size_t)&(((ABC*)0)->c));  
输出结果为

  1. abc : 0022FF44  
OK,目标达成。

现在用宏封装一下

  1. #define container_in(ptr,TYPE,member) \  
  2.     (TYPE*)((unsigned char*)(ptr) - (size_t)&(((TYPE*)0)->member))  
把差值强制转换为(TYPE*)是因为这个宏的目的就是返回(TYPE*)类型的指针

做个测试

  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <string.h>  
  4.   
  5. #define container_in(ptr,TYPE,member) \  
  6.     (TYPE*)((unsigned char*)(ptr) - (size_t)&(((TYPE*)0)->member))  
  7.   
  8. typedef struct  
  9. {  
  10.     char a;  
  11.     char b;  
  12.     char c;  
  13. }TEST1;;  
  14.   
  15. typedef struct  
  16. {  
  17.     char a;  
  18.     char b;  
  19. }TEST2;;  
  20.   
  21. typedef struct  
  22. {  
  23.     char a;  
  24.     TEST1 test1;  
  25.     short b;  
  26.     TEST2 test2;  
  27.     int c;  
  28. }ABC;  
  29.   
  30. int main(void)  
  31. {  
  32.     ABC abc;  
  33.     ABC* p = NULL;  
  34.     abc.a = 1;  
  35.     abc.b = 2;  
  36.     abc.c = 4;  
  37.     p = container_in(&(abc.c),ABC,c);  
  38.     printf("%u %u %u\n",p->a,p->b,p->c);  
  39.     return 0;  
  40. }  
输出结果

  1. 1 2 4  

原文地址:http://blog.csdn.net/ma52103231/article/details/20036705
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值