通过 struct 成员地址 获取 struct 结构体地址

1. 问题描述:

  现在定义了一个结构体:

  struct Foo

  {

    int a;

    int b;

 

  };

  Foo foo;

  假如由于函数传参等原因,现在程序只能拿到 foo.b 的地址,这时想通过某种方法获取到 foo 结构体里的其他成员。

  那么问题来了,这就是以下主要讨论的内容。

2. 原理概述

  将地址 0 强制转换成一个结构体指针,伪代码:  struct foo *p = (struct Foo *)0;

  从而通过已知的结构体成员的地址减去结构体的首地址得到已知结构体成员的内存偏移 , 伪代码 : offset = &(p->b) - p;

  那么问题就简单了, 现在已知 foo.b 的地址,将其减去偏移即可得到该结构体的首地址。

3. 实现举例

 

//file name : list_head.c
#include <stdio.h>

struct list_head
{
    struct list_head *next;
};

struct fox
{
    unsigned int tail_color;
    unsigned int tail_length;
    struct list_head list;
};

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER )

#define container_of(ptr, type, member) ({\
            const typeof( ((type *)0)->member)* __mptr = (ptr);\
            (type *)((char*)__mptr - offsetof(type, member));}) 
int main(int argc, char** argv)
{
    unsigned short offset = 0;
    struct fox *p = 0;
    struct fox red_fox;
    red_fox.tail_color = 45;
    red_fox.tail_length = 10;
    unsigned int *p_t;

    printf("red_fox_addr: %x\n", &red_fox);
    printf("tail_color_addr: %x\n", &(red_fox.tail_color));
    printf("tail_length_addr: %x\n", &(red_fox.tail_length));
    printf("list_addr: %x\n", &(red_fox.list));

//    offset = (unsigned char*)&(p->list) - (unsigned char*)p;    
    offset = offsetof(struct fox, list);
    printf("offset: %d \n", offset);
    
    p_t = container_of(&red_fox.list, struct fox, list);
    printf("red_fox_addr: %x\n", p_t);
    printf("tail_color: %d \n", ((struct fox *)p_t)->tail_color);
    printf("tail_length: %d \n", ((struct fox *)p_t)->tail_length);

    return 0;
}

 

4.  应用

  Linux 中数据结构单链表使用的这种方法。好处也是显而易见的,当用户想通过单链表实现自己封装的数据结构时不需要在单独结构体定义单链表遍历的指针和相关函数,仅仅实现包含 list_head 这个结构体成员即可。而内核提供了完整且高效的用于单链表操作 api.

 

作者能力有限,如发现错误欢迎指正。

 

转载于:https://www.cnblogs.com/firemage/p/5250782.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值