最近在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