您的位置:首页 > 运维架构 > Linux

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

2014-10-09 14:01 537 查看
Linux中有一个宏

[cpp] view
plaincopyprint?





#define container_of(ptr,type,member) 实现略  

实现了通过成员变量地址获取结构体地址的功能。

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

先定义一个结构体吧

[cpp] view
plaincopyprint?





typedef struct  

{  

    int a;  

    int b;  

    int c;  

}ABC;  

再来设计一个函数用来实现功能

[cpp] view
plaincopyprint?





int main(void)  

{  

    ABC abc;  

    printf("abc : %p\n",&(abc));  

    printf("abc.c : %p\n",&(abc.c));  

    return 0;  

}  

main()刚刚好,嘿嘿

输出结果为

[cpp] view
plaincopyprint?





abc : 0022FF44  

abc.c : 0022FF4C  

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

如何求得这个差呢?

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

就是它们的差值

这样

[cpp] view
plaincopyprint?





printf("%u\n",&(((ABC*)0)->c));  

不过编译,运行后会crash掉,因为0这个地址被printf检测到是非法地址,所以得这样

[cpp] view
plaincopyprint?





printf("%u\n",(size_t)&(((ABC*)0)->c));  

这样,传给printf的参数不是一个地址,而是一个普通的常数

好,那么可以求abc地址了

[cpp] view
plaincopyprint?





printf("%p\n",&(abc.c) - (size_t)&(((ABC*)0)->c));  

运行,结果是

[cpp] view
plaincopyprint?





abc : 0022FF2C  

和abc的地址不对啊,为什么呢?

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

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

所以,得这样

[cpp] view
plaincopyprint?





printf("abc : %p\n",(unsigned char*)&(abc.c) - (size_t)&(((ABC*)0)->c));  

输出结果为

[cpp] view
plaincopyprint?





abc : 0022FF44  

OK,目标达成。

现在用宏封装一下

[cpp] view
plaincopyprint?





#define container_in(ptr,TYPE,member) \  

    (TYPE*)((unsigned char*)(ptr) - (size_t)&(((TYPE*)0)->member))  

把差值强制转换为(TYPE*)是因为这个宏的目的就是返回(TYPE*)类型的指针

做个测试

[cpp] view
plaincopyprint?





#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;  

}  

输出结果

[cpp] view
plaincopyprint?





1 2 4  

原文地址:http://blog.csdn.net/ma52103231/article/details/20036705
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux