C语言:计算结构体偏移量的一个小技巧
一. 概述
经常会遇到计算结构体偏移量的需求, 比如有下面这样一个结构体:
struct mav_protocol { char header; char seq; short command_id; char payload[256]; int crc32; } p;
需要在传输到对端前填入它的crc32值,以确保对端在收到这组数据后能够根据填入的crc32值判断收到的这组数据是否仍然正确。
那一般都会有一个公共的函数去计算结构体里某段数据的crc值,函数原型大概如下:
int get_crc32(char *buf, int size) { // 计算CRC... return 0; }
需要传入一个数据指针以及需要计算数据的偏移量,对于我们这个例子来说,需要传入的数据指针就是 struct mav_protocol * , 偏移量就是结构体里crc32这个成员之前的所有数据的长度,也就是 header, seq, command_id...., 等等数据需要参与crc计算。一般计算偏移量的做法是 :
int offset = (unsigned char *)&p.crc32 - (unsigned char *)&p;
然后再代入上面的那个计算crc32的函数:
get_crc32((char *)&p, offset);
今天发现了另一种更巧妙的写法:
二. 具体写法
我看到这哥们直接定义了一个宏:
#define offset(type, v) (&(((type *)0)->v))
然后在使用时直接使用 offset(struct mav_protocol, crc32) 来拿到 crc32这个结构体成员在结构中的偏移量,刚开始很疑惑这种写法,后来反复看了几次之后明白了其中的妙处:
简单的说,既然结构体成员的地址减去结构体的地址就等于该成员的偏移量,那如果结构体的地址为0,该成员的地址就恰好等于它在结构体中的偏移量了。
下面做一个实验来验证这个写法是否正确:
#include <stdio.h> #include <string.h> #define offset(type, v) (&(((type *)0)->v)) int get_crc32(char *buf, int size); struct mav_protocol { char header; char seq; short command_id; char payload[256]; int crc32; } p; int main() { printf("struct p's address is: 0x%x\n", &p); printf("header field's address id: 0x%x\n", &p.header); printf("---------------------------------\n"); printf("crc32 field's address: 0x%x\n", &p.crc32); int offset = (unsigned char *)&p.crc32 - (unsigned char *)&p; printf("offset is: %d\n", offset); printf("-----------------------------------------------------------\n"); printf("crc32 offset: %d\n", offset(struct mav_protocol, crc32)); return 0; }
运行:
struct p's address is: 0x407040
header field's address id: 0x407040
---------------------------------
crc32 field's address: 0x407144
offset is: 260
-----------------------------------------------------------
crc32 offset: 260
可以看到,不管是使用普通的做法还是使用宏的做法得到的结果都是一致的,这样以后需要计算任意结构体成员的偏移量都可以通过这个宏,只传一个结构名和一个结构体成员名就可以了。
而且,无论以后如何调整这个结构体的成员,删除也好,新增也罢,只要保证crc32是它的最后一个成员,计算校验值的代码就无需改动,这样的C语言代码维护起来也是非常省心的。
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探