list_entry(ptr, type, member)——知道结构体内某一成员变量地址,求结构体地址

1 #define list_entry(ptr, type, member) \
2 ((type *)((char *)(ptr) - (unsigned long)(&((type *)0) -> member)))
解释:
1 在0这个地址看做有一个虚拟的type类型的变量,那么取一个成员再取这个成员的地址,就是这个结构体中这个成员的绝对地址 。
2 这句话的意思是获取一个结构体中一个成员在这个结构体中的偏移。type *0是为了计算地址方便。
意思是在0这个地址看做有一个虚拟的type类型的变量,那么取一个成员再取这个成员的地址,就是这个结构体中这个成员的绝对地址,
由于结构体在地址为0的地方,所以这个成员在这个结构体中的相对位置也是这个值了。ptr可能是这个member的指针,而现在想找这
个member所在结构体的地址,所以这个member的地址应该减去这个member在这个结构体中的偏移。然后返回这个结构体类型。

3 实例分析 

1 typedef struct
2 {
3 int i;
4 int j;
5 }exp;

 

这个exp结构体占用8个字节,假设声明一个变量。
exp e1;
那么假如已知e1.j的地址,想知道e1的地址该如何办呢?只要知道j在e1中的偏移,然后把j的地址减去这个偏移就是e1的地址了。在这里,i占据的前4个字节,所以j占据了5-8的字节。现在我们用你给出的list_entry来解释一下。
int *p = e1.j;
假设e1的地址是0x100,那么p就是0x104。可是如何才能比较方便的知道p减去4就是e1的地址呢?尤其是我们可能有时候不知道exp这个结构体里面具体什么样子的。下面的
list_entry(p, exp, j);
变成:
(exp *)((char *)p-(unsigned long)(&((exp *)0)->j)) 
(exp *)0在0地址上面建立8个字节的exp结构体,->j取出这个0地址上exp结构体里的j成员,&((exp *)0)->j)把这个成员地址取出来,由于j在这个结构体里是在5-8字节,所以从0地址数5个字节就是j所在的位置。这种方法省去了我们需要预先知道结构体具体什么样子,结构体里成员的位置怎么安排的。p的地址再减去我们刚算出来j所在的位置,就得到e1的地址。
也就是:
&e1 == list_entry(p, exp, j)
posted @   鸭子船长  阅读(672)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
历史上的今天:
2015-08-28 二叉树中和为某一值的路径
点击右上角即可分享
微信分享提示