通过 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 ...
随机推荐
- SQL Server:替换文本中的回车和换行符
--替换回车符 update master_locationSET street_number = REPLACE(street_number, CHAR(13), '') --替换换行符 updat ...
- js实现刮刮卡效果
<!DOCTYPE html> <html> <body> <canvas/> <script> (function(bodyStyle) ...
- LeetCode 61
Rotate List Given a list, rotate the list to the right by k places, where k is non-negative. For exa ...
- Codeforces Round #191 (Div. 2)
在div 188中,幸运的达成了这学期的一个目标:CF1800+,所以这次可以打星去做div2,有点爽. A.Flipping Game 直接枚举 B. Hungry Sequence 由于素数的分布 ...
- getComputedStyle和currentStyle
/*alert(div.style.width)*/ //null function getstyle(obj,name){ if(obj.currentStyle) { return obj.cur ...
- 从零单排Linux – 1 – 简单命令
从零单排Linux – 1 – 简单命令 Posted in: Linux 从零单排Linux – 1 一.Linux的简单命令: 1.忘记root密码: 读秒时按任意键进入 – e – ↓选择第二个 ...
- Quartz Scheduler(2.2.1) - Integration with Spring
1. maven 依赖: <properties> <spring.version>3.2.3.RELEASE</spring.version> <quart ...
- Git CMD - branch: List, create, or delete branches
命令格式 git branch [--color[=<when>] | --no-color] [-r | -a] [--list] [-v [--abbrev=<length> ...
- HDOJ2025查找最大元素
查找最大元素 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Subm ...
- SQL语句:SQLwhile(0=0)与while @@fetch_status=0.
第一句是SQL循环用的,这个条件下,会读取所有的记录,因为会一直循环; 第二句是游标里的,@@fetch_status=0 等于0时,说明游标是成功的.