[C/C++]struct成员的偏移地址的求法
例如
typedef struct struc {
int a;
char b[20];
double ccc;
};
现想要求 b 相对于 struc 的偏移地址。
其实,很早就知道有 (size_t)&(((struc*)0)->b) 这种写法。昨天,舍友在第三版“面试宝典”上看到这种“怪异”写法,过来问我是怎么回事。
我呢,突然产生“用成员地址 - 结构体地址”的想法。试了一下。
printf("%d ", ((struc*)&(stc.b) - &stc)); // 居然输出 0 !?
但是,分别计算 (struc*)&(stc.b) 和 &stc ,的确相差4字节。// 因为“.”比起地址“&”优先级高,所以 &(stc.b) 就是 &stc.b 。
百思不得其解。遂上论坛发问。答曰:“两个指针相减的结果是两指针的偏移量。这个偏移量是相对于指针类型来说的。比如两int型指针相减,得出一个1,不代表二者地址值之差一个字节,这也是不可能的,因为int 类型一般来说是四字节。所以这个1指的是差的了1个 int 的大小(4字节)。同理, ((struc*)&(stc.b) - &stc) , 差的值还不足一个 struc 类型,自然就是 0 了。 如果想看地址差值,则将他们转成数值类型:(intptr_t)&(stc.b) - (intptr_t)&stc 。” ( 原帖见 http://forum.byr.edu.cn/article/CPP/53484 )
恍然大悟!遂改成
printf("%d ", ((stc.b) - (char*)&stc)); // ok!
printf("%d ", ((char*)(&stc.b) - (char*)&stc)); // 或许这种写法更准确,如果确保 char 是一个字节的话。
又妄想的试了一下
printf("%d ", ((bool*)(&stc.b) - (bool*)&stc));
发现居然也是正确的 ?!
而后,又有高人答曰:“offsetof 一直就是 C 语言标准库的一部分。直接用好了。”
标准库?!心里一惊。赶紧翻阅
裘宗燕.从问题到程序:程序设计与 C 语言引论.北京:机械工业出版社,2005.9,P372
书上曰:“文件<stddef.h> 里包含了标准库的一些常用定义,无论我们包含哪个标准头文件,<stddef.h> 都会被自动包含进来。这个文件里定义:......宏 offsetor ......”
offsetor ?! 难道是印刷错误? 我甚至还找到一篇犯同样的错误的博客! 见 html">http://hi.baidu.com/esta_pessoa/blog/item/ffc91b3f225e95e755e72341.html
看来就是勘误了,因为我的 VS2008 里没有 offsetor ,只有 offsetof 。还有,<stddef.h> 是要明确包含的,至少我的 VS2008 要求这样。好了,赶紧试一下,
printf("%d ", offsetof(stc, stc.b)); // Error!
printf("%d ", offsetof(stc, b)); // 还是 Error!!!
无语。
查 C++ Reference ( http://www.cplusplus.com/reference ),居然要这样
printf("%d ", offsetof(struc, b)); // !!!
虽然还有很多问题不明白,但求偏移地址就到这里吧。
------------------------------------------------------------------------------------------------
总结一下,
对于一个结构体,例如
typedef struct struc {
int a;
char b[20];
double ccc;
};
想要求某一成员,例如 b ,相对于 struc 的偏移地址。
你可以:
// method 1 : 踩着前人的脚步(size_t)&(((struc*)0)->b)
// method 2 : 站在巨人的肩膀上offsetof(struc, b) // NOTE :要明确包含 <stddef.h> 头文件
// method 3 : 走的人多了却也成了路(size_t)((char*)(&stc.b) - (char*)&stc)
补充:软件开发 , C++ ,