通过结构体某个成员的地址计算结构体首地址 (转)

最近在CU论坛上有很多人在问这样一个问题:给出一个结构体成员的地址计算该结构体的起始地址。其实这个题我之前也没有接触过,据说内核代码中有这样用的,但还没有看到。不过觉得这个题的解决方法还是有一定技巧的,就总结一下。下面是实现的代码。

 1 /*
 2 Author: Godbach
 3 Date: Oct 23, 2008
 4 */
 5 #include <stdio.h>
 6 #define STRUCT_OFFSET(stru_name, element) (unsigned long)&((struct stru_name*)0)->element
 7 struct stru_addr
 8 {
 9     int a;
10     char b;
11     int d;
12     char c;
13
14 };
15
16 int main(void)
17 {
18     struct stru_addr s;
19     printf("start addr of s = %x\n", &s.a);
20
21     unsigned long offset = STRUCT_OFFSET(stru_addr, c);
22
23     printf("c_addr = %x, offset = %u\n", &s.c, offset);
24     printf("start addr of s caculated from c addr: %x\n", (char *)&s.c - offset);
25     return 0;
26 }

其实整个程序中最关键的部分就是如何求出结构体中某个成员相对于结构体首地址的偏移量。这里的解决方法是:假设存在一个虚拟地址0,将该地址强制转换成为该结构体指针类型(struct stru_name*)0。那么地址0开始到sizeof(struct)-1长度的内存区域就可以视为一个结构体的内存。这样结构体中任何一个元素都可以通过对该结构体指针解引用得到。由于该结构体的起始地址为0, 因此任何一个成员的地址应该等于其相对于结构体起始地址的偏移,这也就是计算偏移量的方法:(unsigned long)&((struct stru_name*)0)->element。

上面程序执行的结果如下:

1 [[email protected] tmp]# ./a.out
2 start addr of s = bf81b820
3 c_addr = bf81b82c, offset = 12
4 start addr of s caculated from c addr: bf81b820

上述的结果中还同时考虑了结构体内的对齐问题。

原文地址:http://blog.chinaunix.net/uid-10167808-id-25940.html

时间: 2024-10-08 22:04:26

通过结构体某个成员的地址计算结构体首地址 (转)的相关文章

通过结构体某个成员的地址计算结构体首地址

给出一个结构体成员的地址计算该结构体的起始地址,据说内核代码中有这样用的,但还没有看到.不过觉得这个题的解决方法还是有一定技巧的,就总结一下.下面是实现的代码. /* Author: Godbach Date: Oct 23, 2008 */ #include <stdio.h> #define STRUCT_OFFSET(stru_name, element) (unsigned long)&((struct stru_name*)0)->element struct stru

计算结构体首地址的技巧

struct ABC { int a; int b; int c; }; +----------+ <------我们需要计算的是这个地址. | a(4Byte) | +----------+ <------这个地址是已知的. | b(4Byte) | +----------+ | c(4Byte) | +----------+ 通过上图可看出,只需要把当前知道的成员变量的地址ptr,减去它在结构体当中相对偏移量(4),就得到了结构体的首地址(ptr-4). 设计一个type类型的结构体,起始

C语言中结构体内部成员的对齐

说明: ******不同的编译器和处理器,其结构体内部的成员有不同的对齐方式. ******使用sizeof()运算符计算结构体的长度. ###结构体中每个成员相对于结构首地址的偏移量都是成员大小的整数倍,如果有需要编译器会在成员之间加上填充字. ###结构体的总大小是结构体最宽基本类型成员大小的整数倍.如果需要编译器会在最后一个成员之后加上填充字. struct A { <span style="white-space:pre"> </span>unsigne

OpenCV 中结构体IplImage 成员width widthStep使用注意事项

OpenCV 中结构体IplImage 成员width,widthStep使用注意事项 width 是指的图片宽度是多少个像素,而这里widthStep是指的图片中的每一行占用多少个字节. 而且,widthStep会有字节对齐. 当需要对每个像素进行操作的时候,这里最好用widthStep做行递增变换. 比方说这里就是一个例子,明显,ptr_pixel_tmp是指向double类型的三通道图像,而ptr_pixel_img是unsigned char类型的三通道图像,double占八个字节. 于

结构体全局变量成员赋值

struct s { int a; }; s g; g.a = 1; // 编译错误 void f() { g.a = 1; // 编译正确 } 为什么全局结构体变量成员只能在函数内调用? 因为g.a=1是赋值语句,不是初始化语句,赋值语句只能运行的时候可以执行.

结构体访问成员变量什么时候该用“-&gt;”或者是&quot;.&quot;呢?的困惑

煎蛋栗子: typedef struct Node{int data;struct Node *next;}LinkList; LinkList *p=(LinkList *)malloc(sizeof(LinkList)); 在这里,变量p是[LinkList *]类型的[指针变量]它的值是指向某一个[结点]的[地址] 而[(*p)]表示的则是[结点变量],它的值指向的是一个[结点]p是指针,(*p)是结点变量.我们要访问结构体内的成员data 通过指针变量访问:[p]->data通过结点变量

传入的结构体指针强制转为实例化结构体*v

struct val *v = (struct val *)arg;//传入的结构体指针强制转为实例化结构体*v struct val{ int num1; int num2; }; void *text3(void *arg) { struct val *v = (struct val *)arg; int num3=v->num1: int num4=v->num2: printf("arg is v.num1:%d,v.num2:%d\n",num3,num4); /

qsettings 保存自定义结构体(QVariant与自定义结构体相互转化)

参考博文:QVariant与自定义数据类型转换的方法. 这里摘取其关键内容: 1.将自定义数据类型使用Q_DECLARE_METATYPE宏进行声明,便于编译器识别. 2.在插入对象的时候,声明QVariant对象,使用其setValue方法添加自定义对象. 3.在读取的时候,采用QVariant对象的value方法返回自定义对象. 写入: //类型转换 QVariant v; v.setValue(MyStruct);  读取: //转换为自定义的结构体实例 MyStruct s = v.va

结构化数据(structured),半结构化数据(semi-structured),非结构化数据(unstructured)

概念 结构化数据:即行数据,存储在数据库里,可以用二维表结构来逻辑表达实现的数据. 半结构化数据:介于完全结构化数据(如关系型数据库.面向对象数据库中的数据)和完全无结构的数据(如声音.图像文件等)之间的数据,HTML文档就属于半结构化数据.它一般是自描述的,数据的结构和内容混在一起,没有明显的区分. 非结构化数据:不方便用数据库二维逻辑表来表现的数据即称为非结构化数据,包括所有格式的办公文档.文本.图片.XML.HTML.各类报表.图像和音频/视频信息等等. 数据模型 结构化数据:二维表(关系