当前位置: 首页 > news >正文

offsetof宏的实现

题目:写一个宏,计算结构体中某变量相对于首地址的偏移,并给出说明
注:这个题目主要是在考察offsetof宏的实现

1.offsetof函数的定义

#include <stddef.h>  
size_t offsetof(type, member);

但请注意,实际上offsetof是一个宏,而不是一个函数
它接受两个参数:一个结构体类型和一个该类型中的成员名称,并返回该成员在结构体中的字节偏移量
使用举例:

#include <stddef.h>
#include<stdio.h>
struct S 
{double a;int b;char c;
};int main()
{printf("S 结构中的 a 偏移 = %d 字节。\n", (int)offsetof(struct S,a));//0printf("S 结构中的 b 偏移 = %d 字节。\n", (int)offsetof(struct S,b));//8printf("S 结构中的 c 偏移 = %d 字节。\n", (int)offsetof(struct S,c));//12
}

2.offsetof的模拟实现

我们假设结构体起始地址是0,则其成员的地址取出来再强制类型转换为int便可以表示结构体中某个成员相对于起始位置的偏移量

StructType是结构体类型名,MemberName是成员名。具体操作方法是:

  1. 先将0转换为一个结构体类型的指针,相当于某个结构体的首地址是0。此时,每一个成员的偏移量就成了相对0的偏移量,这样就不需要减去首地址了。这只是一个计算技巧,我们并没有真正去访问地址0的内存(否则会导致程序崩溃)
  2. 对该指针用->访问其成员,并取出地址,由于结构体起始地址为0,此时成员偏移量直接相当于对0的偏移量,所以得到的值直接就是对首地址的偏移量
  3. 取出该成员的地址,强转成size_t并打印,就求出了这个偏移量
#define OFFSETOF(StructType, MemberName) (size_t)&(((StructType *)0)->MemberName)// (StructType *)0  *用于将数字0强制转换成一个指向StructType结构体类型的指针
struct StructType
{int a;char c;double d;
};
int main()
{printf("%d\n", OFFSETOF(struct StructType, a));printf("%d\n", OFFSETOF(struct StructType, c));printf("%d\n", OFFSETOF(struct StructType, d));return 0;
}

注意:这里有一个关键点在于,C编译器在编译时就知道结构体内每个成员的精确偏移量,而OFFSEROF宏只是利用编译器的这个知识来获取偏移量数值,并不真正访问内存
这个过程不会影响真实内存
因为这个过程完全发生再编译阶段,而不是运行时:
4. 编译器在编译时就知道结构体的内存布局
5. 当看到这个表达式时,编译器直接计算偏移量数值
6. 最终生成的代码中不包含任何实际访问地址0的操作
7. 结果是一个编译时常量,直接嵌入到最终的可执行文件中

类比理解,可以把其想象成:
8. 你有一张建筑蓝图(结构体定义)
9. 你想知道某个房间距离大楼入口有多远(成员偏移量)
10. 你说:“假设大楼入口在坐标0点,那么房间的坐标就是它距离入口的偏移量”
11. 你不需要真正建造这栋大楼就能计算出这个距离

http://www.dtcms.com/a/359240.html

相关文章:

  • 线程池项目代码细节2
  • 互联网医院系统源码解析:如何从零搭建高效的在线问诊平台
  • SNMPv3开发--EngineID安全访问机制
  • 腾讯云的运维笔记——从yum的安装与更新源开始
  • 深入理解 Linux 驱动中的 file_operations:从 C 语言函数指针到类比 C++ 虚函数表
  • centos7中MySQL 5.7.32 到 5.7.44 升级指南:基于官方二进制包的原地替换式升级
  • 有个需求:切换车队身份实现Fragment的Tab隐藏显示(车队不显示奖赏)
  • SNMPv3开发--简单使用
  • 【Linux基础】深入理解Linux环境下的BIOS机制
  • Python - 机器学习:从 “教电脑认东西” 到 “让机器自己学规律”
  • 项目管理和产品管理的区别
  • docker,mysql安装
  • vector的学习和模拟
  • 揭秘表格推理的“思维革命”:RoT模型介绍
  • 【机器学习基础】机器学习中的容量、欠拟合与过拟合:理论基础与实践指南
  • Vue生命周期、工程化开发和脚手架、组件化开发
  • 学习日志41 python
  • 打工人日报#20250830
  • 内网后渗透攻击--跨域攻击
  • 给某个conda环境安装CUDA 12.4版本 全局CUDA不变
  • Mybatis 动态sql
  • 【树形数据结构】李超线段树 (Li-Chao Tree)
  • 【深度学习新浪潮】有没有什么方法可以将照片变成线描稿,比如日式漫画的那种?
  • 嵌入式学习日记(38)HTTP
  • Ansible主机模式与文件导入技巧
  • 开发环境全面配置指南:语言环境与数据库工具
  • 【面试场景题】订单超时自动取消功能如何设计
  • 【机器学习入门】3.3 FP树算法——高效挖掘频繁项集的“树状神器”
  • 11 C 语言 sizeof 与指针实战指南:一维 / 二维数组计算注意事项 + 笔试真题解析 + sizeof strlen 对比
  • 谈谈线程的中断退出