Linux中有一个宏
#define container_of(ptr,type,member) 实现略实现了通过成员变量地址获取结构体地址的功能。
今天我想好好想想这个实现的原理是怎么来的。
先定义一个结构体吧
typedef struct { int a; int b; int c; }ABC;再来设计一个函数用来实现功能
int main(void) { ABC abc; printf("abc : %p\n",&(abc)); printf("abc.c : %p\n",&(abc.c)); return 0; }main()刚刚好,嘿嘿
输出结果为
abc : 0022FF44 abc.c : 0022FF4C因为成员c的地址比abc高,所以按照数学公式:差 = 成员C地址 - abc地址
如何求得这个差呢?
可以这样,把ABC的一个实例映射到0这个地址,这样成员c的地址就是在0的基础上网上加,进而此时成员c的地址
就是它们的差值
这样
printf("%u\n",&(((ABC*)0)->c));不过编译,运行后会crash掉,因为0这个地址被printf检测到是非法地址,所以得这样
printf("%u\n",(size_t)&(((ABC*)0)->c));这样,传给printf的参数不是一个地址,而是一个普通的常数
好,那么可以求abc地址了
printf("%p\n",&(abc.c) - (size_t)&(((ABC*)0)->c));运行,结果是
abc : 0022FF2C和abc的地址不对啊,为什么呢?
因为此处&(abc.c)这一句有问题。指针的加减操作的步长是按照这个指针的类型来定的,此处c是int型,则它 - 8,其实地址是 - 8 * sizeof(int).
你看,0022FF2C是不是比0022FF44少24.就是因为它上面的操作多减了24
所以,得这样
printf("abc : %p\n",(unsigned char*)&(abc.c) - (size_t)&(((ABC*)0)->c));输出结果为
abc : 0022FF44OK,目标达成。
现在用宏封装一下
#define container_in(ptr,TYPE,member) (TYPE*)((unsigned char*)(ptr) - (size_t)&(((TYPE*)0)->member))把差值强制转换为(TYPE*)是因为这个宏的目的就是返回(TYPE*)类型的指针
做个测试
#include <stdio.h> #include <stdlib.h> #include <string.h> #define container_in(ptr,TYPE,member) (TYPE*)((unsigned char*)(ptr) - (size_t)&(((TYPE*)0)->member)) typedef struct { char a; char b; char c; }TEST1;; typedef struct { char a; char b; }TEST2;; typedef struct { char a; TEST1 test1; short b; TEST2 test2; int c; }ABC; int main(void) { ABC abc; ABC* p = NULL; abc.a = 1; abc.b = 2; abc.c = 4; p = container_in(&(abc.c),ABC,c); printf("%u %u %u\n",p->a,p->b,p->c); return 0; }输出结果
1 2 4
通过成员变量地址获取结构体地址,布布扣,bubuko.com
原文:http://blog.csdn.net/ma52103231/article/details/20036705