1 引言

而在实际开发过程中,比较常见的场景是给定结构体变量的初始地址,如何访问结构体内每一个成员变量?这类问题的核心是如何快速的计算结构体成员变量的偏移地址。本文将和大家一起探讨结构体内成员变量偏移计算的相关知识。

2 结构体偏移问题及计算方法

首先来看下面的一个计算结构体偏移量的问题。

已知结构体类型定义如下:struct node_t{    char a;

int b;

int c;

};

且结构体1Byte对齐#pragma pack(1)

求结构体struct node_t中成员变量c的偏移(这里的偏移量指的是相对于结构体起始位置的偏移量)。

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

解法一

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

有了上述的库函数,用一行代码就可以搞定:offsetof(struct node_t, c);

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

解法二

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

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

先来定义一个结构体变量node:struct node_t node;

接着来计算成员变量c的偏移量:(unsigned long)(&(node.c)) - (unsigned long)(&node)

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

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

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

解法三

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

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

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

几何小问题

这是一道简单的几何问题,假设在座标轴上由A点移动到B点,如何计算B相对于A的偏移?

这个问题对于我们来说是非常的简单,可能大部分人都会脱口而出并得到答案为B-A。

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

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

结合方法2的思路和上述的小问题,是不是很快就得到了下面的关联:(unsigned long)(&(node.c)) - (unsigned long)(&node)

和B - A

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

由于node内存地址==0了,所以node.c      //结构体node中成员变量c

我们就可以使用另外一种方式来表达了,如下:((struct node_t *)0)->c

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

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

此时,我们的偏移求法就消除了struct node_t node这个自定义变量,直接一行代码解决,:(unsigned long)(&(((struct node_t *)0)->c))

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

这里我们将上面的代码功能定义为一个宏,该宏的作用是用来计算某结构体内成员变量的偏移(后面的示例会使用该宏):#define OFFSET_OF(type, member) (unsigned long)(&(((type *)0)->member))

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

OFFSET_OF(struct node_t, c)

3 结论

本文为大家介绍了一种新的c语言中结构体成员变量偏移计算方法,该方法计算量小,且较一般的方法相比,最大的优势在于不需要定义一个结构体变量,就可以直接计算其偏移量。

参考文献

[1]http://isis.poly.edu/kulesh/stuff/src/klist/

[2]https://www.kernel.org/doc/Documentation/CodingStyle

[3]http://www.kroah.com/log/linux/container_of.html

C语言坐标结构,关于c语言结构体偏移的一点思考(一)相关推荐

  1. 关于c语言结构体偏移的一点思考

    注:此处只是利用了编译器的特性来计算结构体偏移 这句话就一笔带过,说得有点牵强附会.以后有时间自己再详细了解一下编译器的特性... more exceptional c++ 中文版 26页 https ...

  2. c语言坐标绕路,C语言中的奇技淫巧

    前言 学习C语言的过程中,总会遇到很多令人眼前一亮的代码,尤其是你写了几十行的代码,别人只用了简单几行的递归就实现的功能.下面我就总结几个C语言中 比较新手向的代码.让你有一种"woc!还能 ...

  3. c语言坐标打符号,c语言中特殊符号

    c语言中特殊符号: 教你用输入法打出任意特殊符号,缺失:c语言中3248/9 最近老有人问我这个符号怎么打,那个符号怎么打. 我每次回答的都是,你要打的是特殊符号,这种特殊符号不能用输入法打出来,需要 ...

  4. c语言坐标打印佛祖,C语言输入平面上两个点的坐标(double类型),计算两个点之间的距离。看”详细“里哪里写错了谢谢...

    满意答案 #include #includeint main(){ int x1,y1,x2,y2,absx,absy; double res; printf("Please input t ...

  5. 编写C语言代码,实现以下功能:输入平面上两个点P1(x1,y1)和P2(x2,y2)的坐标,以这两个点为左上角和右下角可以确定一个矩形,输出这个矩形的周长。要求平面上点的坐标和矩形都用结构体来表示。

    编写C语言代码,实现以下功能: 输入平面上两个点P1(x1,y1)和P2(x2,y2)的坐标,以这两个点为左上角和右下角可以确定一个矩形,输出这个矩形的周长.要求平面上点的坐标和矩形都用结构体来表示. ...

  6. java链式结构_java语言实现队列顺序结构与链式结构

    本文主要向大家介绍了java语言实现队列顺序结构与链式结构,通过具体的内容向大家展示,希望对大家学习java语言有所帮助. 队列的顺序存储结构实现 public class Queue{ privat ...

  7. 《C程序设计语言》笔记 第6章 结构

    结构(structure)是一个或多个变量的集合,这些变量可能是不同的类型,为了方便处理而组织在一个名字之下.由于结构将一组相关的变量看作一个单元而不是各自独立的实体,因此结构有助于组织复杂的数据,特 ...

  8. 简单介绍C语言使用四种方法初始化结构体

    这篇文章说明了什么是结构体,介绍了结构体的概念和使用优点,在C语言中如何使用和初始化结构体方法,通过详细的代码展开进行说明,希望该篇文章对你有所帮助 什么是结构体 在实际问题中,一组数据往往有很多种不 ...

  9. C语言程序设计有哪几种结构,第章c语言程序设计的三种基本结构.ppt

    第章c语言程序设计的三种基本结构 北京科技大学 计算机系 第2章 C语言程序设计 的三种基本结构 2.1 顺序结构程序设计 2.1.1 C语句 2.1.2 字符数据的输入与输出 2.1.3 格式输入与 ...

最新文章

  1. TSNE Understanding
  2. Oracle备份恢复一(手动备份)
  3. 关于android Activity生命周期的说明
  4. BigData/Cloud Computing:购买并登录Windows弹性云服务器之详细攻略(图文教程)—更优惠、更贴心!
  5. Circle HDU - 6550 (数学)
  6. KBMMW 4.81.00 发布
  7. 【Codeforces Round #422 (Div. 2) C】Hacker, pack your bags!(二分写法)
  8. 收藏几个漂亮的login页面验证
  9. JavaScript是什么意思?
  10. Mathematica图像处理
  11. FFmpeg+dxva2 H265硬解码 下方出现绿条或被下方拉长
  12. 黑苹果alc269声卡仿冒id_笔记本制作仿冒声卡驱动AppleHDA最详细教程
  13. PHPoffice PHPword添加水印
  14. rtklib-单点定位(pntpos.c)代码关键问题解析-satposs部分
  15. Arduino基础篇(二)-- 常用的基本函数
  16. 小米MAX3 线刷兼救砖_解账户锁_纯净刷机包_教程
  17. 分享、活动、地推、广告:openinstall全渠道多场景解决方案
  18. vba控制图表,excel图表,一键完成
  19. RecyclerView最后一条显示不全
  20. NFT:使用 EIP-2981 开启 NFT 版税之旅

热门文章

  1. 第20篇 项目进度管理__项目进度管理的含义和作用
  2. sklearn库(即scikit-learn)的pip安装
  3. 基于单片机全自动洗衣机仿真设计-protues仿真
  4. 移动端与大屏幕自适应适配方案
  5. 制作数据集(二)--为图片数据集打上标签并保存为txt文件
  6. Python入门程序【八】
  7. OpenSearch在线干预服务
  8. 科学计算机eq7,HiPER Calc Pro(多功能科学计算器)
  9. Axure| Axure如何画线
  10. 两会2023农业划重点 农民丰收节-万祥军:议案提案农业声音