• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >C语言 > 详解C语言的结构体中成员变量偏移问题

详解C语言的结构体中成员变量偏移问题

作者: 字体:[增加 减小] 来源:互联网 时间:2017-05-28

通过本文主要向大家介绍了c语言指针详解,c语言题库及详解答案,c语言关键字详解,c语言链表详解,c语言32关键字详解等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

c语言中关于结构体的位置偏移原则简单,但经常忘记,做点笔记以是个记忆的好办法

原则有三个:

a.结构体中的所有成员其首地址偏移量必须为器数据类型长度的整数被,其中第一个成员的首地址偏移量为0,

例如,若第二个成员类型为int,则其首地址偏移量必须为4的倍数,否则就要“首部填充”;以此类推

b.结构体所占的总字节数即sizeof()函数返回的值必须是最大成员的长度的整数倍,否则要进行“末尾填充”;

c.若结构体A将结构体B作为其成员,则结构体B存储的首地址的偏移量必须为B中所含成员数据长度最大值的整数倍,

如若B中成员为int,double,char,则B的偏移量要为8的整数倍;否则进行“中间填充”。

相信大家在c语言程序开发的过程一定都使用过结构体,那么不知你对结构体中成员变量偏移这块是如何理解的?本文将和大家一起分享下,本人最近关于c语言中结构体偏移的一些思考和总结。

示例1

我们先来定义一下需求:

已知结构体类型定义如下:

struct node_t{
 char a;
 int b;
 int c;
};
</div>

且结构体1Byte对齐

#pragma pack(1)
</div>

求:

结构体struct node_t中成员变量c的偏移。

注:这里的偏移量指的是相对于结构体起始位置的偏移量。

看到这个问题的时候,我相信不同的人脑中浮现的解决方法可能会有所差异,下面我们分析以下几种可能的解法:

方法1

如果你对c语言的库函数比较熟悉的话,那么你第一个想到的肯定是offsetof函数(其实只是个宏而已,先姑且这样叫着吧),我们man 3 offsetof查看函数原型如下:

 #include <stddef.h>

  size_t offsetof(type, member);

</div>

有了上述的库函数,我们用一行代码就可以搞定:

offsetof(struct node_t, c);
</div>

当然这并非本文探讨的重点,请继续阅读。


方法2

当我们对c语言的库函数不熟悉的时候,此时也不要着急,我们依然可以使用我们自己的方法来解决问题。

最直接的思路是:【结构体成员变量c的地址】 减去 【结构体起始地址】

我们先来定义一个结构体变量node:

struct node_t node;
</div>

接着来计算成员变量c的偏移量:

(unsigned long)(&(node.c)) - (unsigned long)(&node)

</div> &(node.c)为结构体成员变量c的地址,并强制转化为unsigned long;</div>

&node为结构体的起始地址,也强制转化为unsigned long;

最后我们将上述两值相减,得到成员变量c的偏移量;

方法3

按照方法2的思路我们在不借助库函数的情况下,依然可以得到成员变量c的偏移量。但作为程序员,我们应该善于思考,是不是可以针对上面的代码做一些改进,使我们的代码变得更简洁一些?在做具体的改进之前,我们应该分析方法2存在哪些方面的问题。

相信不用我多说,细心的你一定已经察觉到,方法2中最主要的一个问题是我们自定义了一个结构体变量node,虽然题目中并未限制我们可以自定义变量,但当我们遇到比较严且题目中不允许自定义变量的时候,此时我们就要思考新的解决方法。

在探讨新的解决方法之前,我们先来探讨一个有关偏移的小问题:

小问题

这是一道简单的几何问题,假设在座标轴上由A点移动到B点,如何计算B相对于A的偏移?这个问题对于我们来说是非常的简单,可能大部分人都会脱口而出并得到答案为B-A。

那么这个答案是否完全准确呢?比较严谨的你觉得显然不是,原因在于,当A为坐标原点即A=0的时候,上述答案B-A就直接简化为B了。

这个小小的简单的问题,对于我们来说有什么启示呢?

我们结合方法2的思路和上述的小问题,是不是很快就得到了下面的关联:

(unsigned long)(&(node.c)) - (unsigned long)(&node)
</div>

和

B - A
我们小问题的思路是当A为坐标原点的时候,B-A就简化为B了,那么对应到我们的方法2,当node的内存地址为0即(&node==0)的时候,上面的代码可简化为:

(unsigned long)(&(node.c))
</div>

由于node内存地址==0了,所以

node.c  //结构体node中成员变量c
</div>

我们就可以使用另外一种方式来表达了,如下:

((struct node_t *)0)->c
</div>

上述代码应该比较好理解,由于我们知道结构体的内存地址编号为0,所以我们就可以直接通过内存地址的方式来访问该结构体的成员变量,相应的代码的含义就是 获取内存地址编号为0的结构体struct node_t的成员变量c。

注:此处只是利用了编译器的特性来计算结构体偏移,并未对内存地址0有任何操作,有些同学对此可能还有些疑问,详细的了解该问题可参考关于c语言结构体成员变量访问方式的一点思考。

此时,我们的偏移求法就消除了struct node_t node这个自定义变量,直接一行代码解决,:

(unsigned long)(&(((struct node_t *)0)->c))
</div>

上述的代码相对于方法2是不是更简洁了一些。

这里我们将上面的代码功能定义为一个宏,该宏的作用是用来计算某结构体内成员变量的偏移(后面的示例会使用该宏):

#define OFFSET_OF(type, member) (unsigned long)(&(((type *)0)->member))
</div>

使用上面的宏,就可以直接得到成员变量c在结构体struct node_t中的偏移为:

OFFSET_OF(struct node_t, c)

</div>

示例2

和示例1一样,我们先定义需求如下:

已知结构体类型定义如下:

struct node_t{
 char a;
 int b;
 int c;
};
</div>

int *p_c,该指针指向struct node_t x的成员变量c

结构体1Byte对齐

#pragma pack(1)
求:

结构体x的成员变量b的值?

拿到这个问题的时候,我们先做一下简单的分析,题目的意思是根据一个指向某结构体成员变量的指针,如何求该结构体的另外一个成员变量的值。

那么可能的几种解法有:

方法1

由于我们知道结构体是1Byte对齐的,所以这道题最简单的解法是:

*(int *)((unsigned long)p_c - sizeof(int))
上述代码很简单,成员变量c的地址减去sizeof(int)从而得到成员变量b的地址,然后再强制转换为int *,最后再取值最终得到成员变量b的值;

方法2

方法1的代码虽然简单,但扩展性不够好。我们希望通过p_c直接得到指向该结构体的指针p_node,然后通过p_node访问该结构体的任意成员变量了。

由此我们得到计算结构体起始地址p_node的思路为:

【成员变量c的地址p_c】减去【c在结构体中的偏移】

由示例1,我们得到结构体struct node_t中成员变量c的偏移为:

(unsigned long)&(((struct node_t *)0)->c)
</div>

所以我们得到结构体的起始地址指针p_node为:

(struct node_t *)((unsigned long)p_c - (unsigned long)(&((struct node_t *)0)->c))
</div>

我们也可以直接使用示例1中定义的OFFSET_OF宏,则上面的代码变为:

(struct node_t *)((unsigned long)p_c - OFFSET_OF(struct node_t, c))
</div>

最后我们就可以使用下面的代码来获取成员变量a,b的值:

p_node->a

p_node->b

</div>

我们同样将上述代码的功能定义为如下宏:

#define STRUCT_ENTRY(ptr, type, member) (type *)((unsigned long)(ptr)-OFFSET_OF(type, member))</div> </div> 该宏的功能是通过结构体任意成员变量的指针来获得指向该结构体的指针。</div> </div>

我们使用上面的宏来修改之前的代码如下:

STRUCT_ENTRY(p_c, struct node_t, c)
</div>

p_c为指向结构体s

分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • C语言中条件编译详解
  • C语言中强制地址跳转详解
  • 详解C 语言项目中.h文件和.c文件的关系
  • C语言中 值传递和指针传递实例详解
  • 详解C语言中的函数、数组与指针
  • C语言 坐标移动详解及实例代码
  • 详解C语言中的字符串拼接(堆与栈)
  • C语言 经典题目螺旋矩阵 实例详解
  • C语言 文件操作解析详解及实例代码
  • C语言 冒泡排序算法详解及实例

相关文章

  • 2017-05-28Linux 软件看门狗 watchdog使用介绍
  • 2017-05-28MFC程序对文件的处理方法
  • 2017-05-28老生常谈C语言静态函数库的制作和使用
  • 2017-05-28c++实现加载so动态库中的资源
  • 2017-05-28深入分析C语言分解质因数的实现方法
  • 2017-05-28将正小数转化为2-9进制小数的实现方法
  • 2017-05-28浅谈C++中派生类对象的内存布局
  • 2017-05-28C基础 redis缓存访问详解
  • 2017-05-28内部排序之堆排序的实现详解
  • 2017-05-28C++空类默认函数详细解析

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • C++设计模式编程中proxy代理模式的使用实例
    • C++实现判断字符串是否回文实例解析
    • C++快速幂与大数取模算法示例
    • C语言 以数据块的形式读写文件详解及实现代码
    • 利用C/C++二进制读写png文件的方法示例
    • C++利用stringstream进行数据类型转换实例
    • 八皇后问题的相关C++代码解答示例
    • 筛选法的C++实现
    • C语言 结构体数组详解及示例代码
    • C++中“#”号的使用技巧

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有