`

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

阅读更多

例如
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///////////////////////////////////////////////////////////

0
1
分享到:
评论

相关推荐

    c/c++中struct定义、声明、对齐方式解析

    C/C++中struct定义、声明、对齐方式解析 struct是C/C++编程语言中的一种数据类型,用于组合多个变量以形成一个新的数据类型。struct的定义、声明和对齐方式是C/C++编程中非常重要的概念,本文将对struct的定义、...

    词法分析示例程序(C语言编写,针对PL/0语言)

    5. 定义了`struct instruction`结构体,它包含了指令的功能代码(fct)、作用域级别(level)和地址偏移(address),这是构建目标代码的基本单元。 6. 其他变量如`num`存储最近读取的数字,`cc`、`ll`记录字符计数...

    C/C++获取目录下的文件列表信息

    在C/C++编程中,获取目录下的文件列表信息是一项常见的任务,这通常涉及到操作系统底层的文件系统操作。这里我们将深入探讨如何实现这一功能,并提供一个跨平台的代码示例。 首先,我们需要了解与目录和文件列表...

    嵌入式C C++语言精华.pdf

    #### C/C++结构体的一个高级特性——指定成员的位数 - **知识点一:位域的概念** - 位域允许在一个字节或更大的整数中划分出不同大小的空间来存储不同类型的值。 - 通过使用位域,可以在一定程度上节省内存空间,...

    C与C++笔试总结

    - 逻辑地址是段地址与段内偏移地址的组合,物理地址等于段地址左移4位后与段内偏移地址相加。 9. **C++中的类型转换方式** - 静态类型转换(static_cast) - 动态类型转换(dynamic_cast) - 无保护类型转换...

    bmp.rar_图片显示_C/C++_

    C/C++语言虽然不像Python或Java那样内置了丰富的图像处理库,但通过直接操作文件字节流,我们可以实现对BMP文件的读取和解析。这个"bmp.rar"压缩包包含了一个名为“bmp.h”的头文件,很可能提供了用于读取BMP文件的...

    嵌入式系统编程修炼 arm linux c

    例如,`struct`中的成员可能会根据其大小自动调整偏移量,使得它们的地址能够满足特定的对齐要求。 #### 2.2 对齐指令 使用`#pragma pack`可以控制编译器如何处理结构体中的成员对齐。例如: ```c #pragma pack(8)...

    传智播客扫地僧视频讲义源码

    本教程共分为5个部分,第一部分是C语言提高部分,第二部分为C++基础部分,第三部分为C++进阶部分,第四部分为C、C++及数据结构基础部分,第五部分为C_C++与设计模式基础,内容非常详细. 第一部分 C语言提高部分目录...

    详说如何用C,C++和JAVA读入和保存位图

    ### 如何用C,C++和JAVA读入和保存位图 #### 一、位图基础知识及文件结构 本文档由彭千贺撰写,详细介绍了如何利用C、C++和JAVA语言读取与保存位图文件。位图(Bitmap)是一种常见的图形格式,广泛应用于计算机图像...

    c、c++中的时间函数

    在C和C++编程语言中,时间函数是一个重要的部分,特别是在需要进行计时、日志记录、性能测试或实现时间相关的功能时。本篇文章将深入探讨C和C++中的时间函数,以及如何在Windows环境下使用它们。 首先,我们需要...

    嵌入式C 精华总结

    extern"C"在C++中用于防止C++对函数名进行名称修饰,保证在C++代码中能正确链接到C语言编写的库函数。在嵌入式开发中,经常需要链接C语言编写的库,因此理解extern"C"的用法对于编写可移植代码至关重要。 void指针...

    Visual C++ vc对象模型

    C++基于C语言设计,因此在结构体(`struct`)的内存布局方面遵循C语言的规则:成员变量按声明顺序排列,并根据具体实现的对齐策略在内存中对齐。例如,在C++中定义了一个简单的结构`A`: ```cpp struct A { char c...

    c++编程内存扩充算法

    通常,内存扩充可以通过操作系统提供的API或者通过C/C++语言库函数实现。 ### 2. 文件结构与内存管理类定义 #### 文件头定义 ```cpp #ifndef XRH_XMS_LIBRARY #define XRH_XMS_LIBRARY ``` 这一段代码用于避免该...

Global site tag (gtag.js) - Google Analytics