通过 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 *))->member)* __mptr = (ptr);\
(type *)((char*)__mptr - offsetof(type, member));})
int main(int argc, char** argv)
{
unsigned short offset = ;
struct fox *p = ;
struct fox red_fox;
red_fox.tail_color = ;
red_fox.tail_length = ;
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 ;
}
4. 应用
Linux 中数据结构单链表使用的这种方法。好处也是显而易见的,当用户想通过单链表实现自己封装的数据结构时不需要在单独结构体定义单链表遍历的指针和相关函数,仅仅实现包含 list_head 这个结构体成员即可。而内核提供了完整且高效的用于单链表操作 api.
作者能力有限,如发现错误欢迎指正。
通过 struct 成员地址 获取 struct 结构体地址的更多相关文章
- list_entry(ptr, type, member)——知道结构体内某一成员变量地址,求结构体地址
#define list_entry(ptr, type, member) \ ((type *)(() -> member))) 解释: 1 在0这个地址看做有一个虚拟的type类型的变量,那 ...
- Linux中的两个经典宏定义:获取结构体成员地址,根据成员地址获得结构体地址;Linux中双向链表的经典实现。
倘若你查看过Linux Kernel的源码,那么你对 offsetof 和 container_of 这两个宏应该不陌生.这两个宏最初是极客写出的,后来在Linux内核中被推广使用. 1. offse ...
- 由结构体成员地址计算结构体地址——list_entry()原理详解
#define list_entry(ptr, type, member) container_of(ptr, type, member) 在进行编程的时候,我们经常在知道结构体地址的情况下,寻找其中 ...
- typedef struct xxx xxx与struct xxx区别 && “->”和“.”访问结构体变量
1. struct //是C中的结构体的关键词.如: stuct node{ int a;.....} a; node 相当于结构体的类型,关键是其实在C中stuct node 才相当于一个数据类型, ...
- nginx取结构体地址
linux内核提供了一个container_of()宏,可以根据结构体某个成员的地址找到父结构的地址. #define container_of(ptr, type, member) ({ \ con ...
- 获取客户机MAC地址 根据IP地址 获取机器的MAC地址 / 获取真实Ip地址
[DllImport("Iphlpapi.dll")] private static extern int SendARP(Int32 dest, Int32 host, ref ...
- struct的成员对齐问题-结构体实际大小问题
struct的成员对齐 注意:为了方便说明,等号左边是每个数据单独所占长度,右边是最终空间大小,以字节为单位. 一.什么时间存在对其问题:(32位机对齐方式是按照4字节对其的,以下所有试验都是在32位 ...
- C语言根据结构体成员变量的地址,得到结构体的地址
看nginx代码时发现双链表使用的是这种方法,记录一下 给出一个实例来说明 struct father_t { int a; char *b; double c;}f;char *p ...
- golang中内存地址计算-根据内存地址获取下一个内存地址对应的值
package main import ( "fmt" "unsafe" ) func main() { // 根据内存地址获取下一个字节内存地址对应的值 da ...
随机推荐
- oracle顺序控制语句goto、null和分页过程中输入输出存储、java程序的调用过程
顺序控制语句1 goto建议不要使用 declare i number:=; begin loop dbms_output.put_line(i); then goto end_loop; end i ...
- Android二手交易平台,dagger2+mvp+Bmob后台云搭建
二手交易平台 我的毕业设计项目安卓源码,二手交易平台,dagger2+mvp+Bmob后台云搭建,集成了百度地图,友盟三方登录等 系统架构 Dagger2+MVP分层,完成了一次正常的retrofit ...
- iOS XMPP(1)
关键词: 即时通讯技术 协议 了解xmpp的目的,工作原理 XMPP是基于XML的协议,传送的是XML格式流;IP地址:联网时电脑的唯一标识 Mac地址:不联网时电脑的唯一标志; OSI七层 ...
- [改善Java代码]不能初始化泛型参数和数组
泛型类型在编译期被擦除,我们在类初始化时将无法获得泛型的具体参数,比如这样的代码: class Foo<T>{ //private T t =new T();//报错Cannot inst ...
- 关于使用vss版本管理工具中的sln,suo文件作用
Visual Studio.NET采用两种文件类型(.sln和.suo)来存储特定于解决方案的设置,它们总称为解决方案文件.为解决方案资源管理器提供显示管理文件的图形接口所需的信息 从而在每次继续开发 ...
- poj 2942 点的双连通分量
思路: 对于该图,直接用建图貌似没法解,所以也很容易想到建补图,这样存在边的两个点就能再圆桌上做一起.也就将问题转化为对双连通分量中是否存在奇圈了. 我们将每次查询的边保存在stack中,当遇到关键点 ...
- poj3264
Balanced Lineup Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 45777 Accepted: 21499 ...
- 关于Winform发布时,资源文件缺失的解决方案
今天和大家分享一下,我这几天一直困惑的问题,今天不经意间解决了这个问题,接下来描述一下这个问题: 问题: 最近公司给人家做二次开发,是C/S结构的,我在做Winform时发现,当我选择一个项目发布时, ...
- live(),bind(),delegate()等事件绑定方法的区别及应用解析
1 首先bind()方法是最直观的,但是也是弊端最大的. $('a').bind('click',function(){alert('that tickles!')}) 这和事件冒泡有直接关系,当我们 ...
- SQL_CURSOR_游标循环
) DECLARE My_Cursor CURSOR --定义游标 FOR (SELECT column1 FROM #temp1) --查出需要的集合放到游标中 OPEN My_Cursor; -- ...