[C/C++] struct 成员的偏移地址的求法

本文探讨了C语言中结构体成员相对于结构体起始位置的偏移地址计算方法,包括使用指针运算、offsetof宏及不同类型的指针转换等技巧,并详细解释了各种方法的原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

例如
typedef struct struc {
     int a;
     char b[20];
     double ccc;
};

  
现想要求 b 相对于 struc 的偏移地址。


其实,很早就知道有 (size_t)&(((struc*)0)->b) 这种写法。昨天,舍友在第三版“面试宝典”上看到这种“怪异”写法,过来问我是怎么回事。


我呢,突然产生“用成员地址 - 结构体地址”的想法。试了一下。


printf("%d\n", ((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\n", ((stc.b) - (char*)&stc)); // ok!


printf("%d\n", ((char*)(&stc.b) - (char*)&stc)); // 或许这种写法更准确,如果确保 char 是一个字节的话。


又妄想的试了一下


printf("%d\n", ((bool*)(&stc.b) - (bool*)&stc));


发现居然也是正确的 ?!


而后,又有高人答曰:“offsetof 一直就是 C 语言标准库的一部分。直接用好了。”


标准库?!心里一惊。赶紧翻阅


裘宗燕.从问题到程序:程序设计与 C 语言引论.北京:机械工业出版社,2005.9,P372


书上曰:“文件<stddef.h> 里包含了标准库的一些常用定义,无论我们包含哪个标准头文件,<stddef.h> 都会被自动包含进来。这个文件里定义:......宏 offsetor ......”


offsetor ?! 难道是印刷错误? 我甚至还找到一篇犯同样的错误的博客! 见 http://hi.baidu.com/esta_pessoa/blog/item/ffc91b3f225e95e755e72341.html


看来就是勘误了,因为我的 VS2008 里没有 offsetor ,只有 offsetof 。还有,<stddef.h> 是要明确包含的,至少我的 VS2008 要求这样。好了,赶紧试一下,


printf("%d\n", offsetof(stc, stc.b)); // Error!


printf("%d\n", offsetof(stc, b)); // 还是 Error!!!


无语。


查 C++ Reference ( http://www.cplusplus.com/reference ),居然要这样


printf("%d\n", 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)

 

 

///////////////////////////////////////////////////////////END///////////////////////////////////////////////////////////

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值