在 C 语言开发中,结构体(struct)是极其高频的数据类型。

无论是网络协议、嵌入式开发、Linux 内核,还是数据库底层实现,结构体都承担着“组织内存数据”的核心角色。

而在实际开发中,我们经常会遇到这样一个问题:

如何获取结构体成员相对于结构体首地址的偏移量?

例如:


struct Test
{
    char a;
    int  b;
    char c;
};

我们可能想知道:

  • a 距离结构体起始位置多少字节?
  • b 的偏移量是多少?
  • 为什么 b 不是紧跟在 a 后面?

这时,标准库中的 offsetof 宏就派上用场了。

今天我们不仅会手写实现它,还会彻底吃透它背后的:

  • 编译期计算
  • 虚拟 0 地址
  • 指针运算
  • 内存对齐
  • 常量折叠

等核心原理。


一、offsetof 到底是什么?

C 标准库 <stddef.h> 中提供了一个经典宏:


offsetof(type, member)

作用:

计算结构体成员相对于结构体起始地址的字节偏移量。

例如:


#include <stdio.h>
#include <stddef.h>

struct Test
{
    char a;
    int  b;
    char c;
};

int main()
{
    printf("%zu\n", offsetof(struct Test, a));
    printf("%zu\n", offsetof(struct Test, b));
    printf("%zu\n", offsetof(struct Test, c));

    return 0;
}

运行结果:


0
4
8

很多人第一次看到会疑惑:


a 为啥是 0
b 为啥不是 1
c 为啥不是 5

这就涉及到:

结构体内存对齐

后面我们会详细解释。


二、手写实现 offsetof 宏

实际上,offsetof 的核心实现极其经典:


#define OFFSET_OF(type, member) \
    ((size_t)&(((type *)0)->member))

看起来很短,但信息量巨大。

我们一步一步拆开。


三、宏的执行过程详解

假设:


struct Test
{
    char a;
    int  b;
    char c;
};

现在执行:


OFFSET_OF(struct Test, b)

宏展开后:


((size_t)&(((struct Test *)0)->b))

继续拆解。


3.1 (struct Test *)0

先把整数 0 强转成结构体指针:


(struct Test *)0

意思是:

假设结构体起始地址在内存 0 地址处。

注意:

这里仅仅是“假设”。

并没有真正访问 0 地址。


3.2 ->b

接下来:


((struct Test *)0)->b

等价于:


(*(struct Test *)0).b

逻辑上表示:

如果结构体从 0 地址开始,那么成员 b 在哪里?

编译器此时会根据结构体布局规则,直接算出:


b 在 offset = 4 的位置

3.3 &

然后取地址:


&(((struct Test *)0)->b)

结果:


地址值 = 4

最终:


(size_t)4

于是:


offsetof(struct Test, b)

结果就是:


4

四、最容易误解的问题

很多初学者看到这里都会产生一个巨大疑问:

“0 地址不是非法地址吗?”

没错。

运行时访问 0 地址会直接崩溃。

例如:


int *p = 0;
printf("%d\n", *p);

会导致:


Segmentation Fault

offsetof 不会。

原因是:

offsetof 属于编译期常量计算

它根本不会在运行时访问内存。


五、offsetof 的本质:编译期计算

整个过程分三步:


5.1 预处理阶段

宏仅做文本替换:


OFFSET_OF(struct Test, b)

变成:


((size_t)&(((struct Test *)0)->b))

此时不做任何计算。


5.2 编译阶段

编译器发现:

  • 没有变量
  • 没有函数调用
  • 没有动态行为

这是一个:

常量表达式

于是编译器直接完成:


结构体布局分析

然后得出:


b 偏移量 = 4

直接把结果写进目标文件。


5.3 最终生成的机器码

最终程序中可能只剩:


mov eax, 4

甚至连这条都没有。

因为编译器可能进一步优化。

也就是说:

offsetof 几乎零运行时开销

这就是它强大的地方。


六、为什么会发生内存对齐?

现在解释之前的问题:

为什么:


struct Test
{
    char a;
    int  b;
    char c;
};

偏移量是:


a = 0
b = 4
c = 8

而不是:


0 1 5

原因:

CPU 访问内存时更喜欢“对齐访问”

例如:

  • int 通常要求 4 字节对齐
  • double 通常要求 8 字节对齐

因此:


char a;

占 1 字节后:


0

接下来 int b 需要放到 4 的整数倍地址。

于是:


1 2 3

这三个字节被填充(padding)。

所以:


b 从 4 开始

然后:


c 位于 8

结构体实际布局:


地址: 0   1 2 3   4 5 6 7   8
数据: a   padding  b        c

七、完整测试代码

下面给出完整示例:


#include <stdio.h>
#include <stddef.h>

#define OFFSET_OF(type, member) \
    ((size_t)&(((type *)0)->member))

struct Test
{
    char a;
    int  b;
    char c;
};

int main()
{
    printf("a 偏移量: %zu\n",
           OFFSET_OF(struct Test, a));

    printf("b 偏移量: %zu\n",
           OFFSET_OF(struct Test, b));

    printf("c 偏移量: %zu\n",
           OFFSET_OF(struct Test, c));

    return 0;
}

输出:


a 偏移量: 0
b 偏移量: 4
c 偏移量: 8

八、offsetof 在 Linux 内核中的经典应用

Linux 内核大量使用:


container_of

宏。

其底层核心就是:


offsetof

例如:


container_of(ptr, type, member)

可以通过:

  • 成员地址
  • 成员偏移量

反推出:

整个结构体对象地址

这是:

  • Linux 链表
  • 驱动开发
  • 面向对象 C 编程

的底层核心技巧。


九、数组也能使用同类思想

数组本质也是连续内存。

因此同样可以计算偏移:


#define ARR_OFFSET(type, idx) \
    ((size_t)&(((type *)0)[idx]))

例如:


printf("%zu\n", ARR_OFFSET(int, 3));

结果:


12

因为:


3 * sizeof(int)
= 12

十、offsetof 的使用注意事项

1)不要真的访问 0 地址

错误示例:


int *p = 0;
*p = 100;

这是运行时行为。

会直接崩溃。


2)offsetof 依赖编译器布局规则

不同平台:

  • 对齐方式
  • ABI
  • 编译器

可能不同。

因此偏移量不一定跨平台一致。


3)不能用于普通变量

它适用于:

  • struct
  • union

等聚合类型。


十一、offsetof 为什么如此经典?

因为它把 C 语言几个核心知识点串联到了一起:

  • 指针本质
  • 地址计算
  • 编译期优化
  • 常量折叠
  • 内存布局
  • CPU 对齐
  • ABI 规则

很多人第一次真正理解:


((type*)0)->member

时,才算真正进入了:

C 语言底层世界


十二、总结

offsetof 看似只有一行代码:


#define OFFSET_OF(type, member) \
    ((size_t)&(((type *)0)->member))

但它背后体现的是:

  • 编译器如何分析结构体
  • CPU 为什么需要对齐
  • 常量表达式如何优化
  • C 语言如何直接操作内存模型

它也是:

  • Linux 内核
  • 驱动开发
  • 嵌入式系统
  • 高性能框架

中极其重要的基础知识。

真正理解它之后,你会对:

“编译期行为”和“运行时行为”

有本质级的认识。

编程语言C++www.share.tailixy.com++C语言的魅力
编程语言C++m.www.tailixy.com++C语言的魅力
编程语言C++m.share.tailixy.com++C语言的魅力
编程语言C++www.blog.tailixy.com++C语言的魅力
编程语言C++read.share.tailixy.com++C语言的魅力
编程语言C++www.share.hengyuanna.com++C语言的魅力
编程语言C++m.www.hengyuanna.com++C语言的魅力
编程语言C++m.share.hengyuanna.com++C语言的魅力
编程语言C++www.blog.hengyuanna.com++C语言的魅力
编程语言C++read.share.hengyuanna.com++C语言的魅力
编程语言C++xc2035.com++C语言的魅力
编程语言C++tailixy.com++C语言的魅力
编程语言C++www.tailixy.com++C语言的魅力
编程语言C++www.xc2035.com++C语言的魅力
编程语言C++www.share.xc2035.com++C语言的魅力
编程语言C++m.www.xc2035.com++C语言的魅力
编程语言C++m.share.xc2035.com++C语言的魅力
编程语言C++www.blog.xc2035.com++C语言的魅力
编程语言C++read.share.xc2035.com++C语言的魅力
编程语言C++haopgz.com++C语言的魅力
编程语言C++hengyuanna.com++C语言的魅力
编程语言C++www.hengyuanna.com++C语言的魅力
编程语言C++www.haopgz.com++C语言的魅力
编程语言C++www.share.haopgz.com++C语言的魅力
编程语言C++m.www.haopgz.com++C语言的魅力
编程语言C++m.share.haopgz.com++C语言的魅力
编程语言C++www.blog.haopgz.com++C语言的魅力
编程语言C++read.share.haopgz.com++C语言的魅力
编程语言C++wuhang-tinpack.com++C语言的魅力
编程语言C++www.wuhang-tinpack.com++C语言的魅力
编程语言C++www.share.wuhang-tinpack.com++C语言的魅力
编程语言C++m.www.wuhang-tinpack.com++C语言的魅力
编程语言C++m.share.wuhang-tinpack.com++C语言的魅力
编程语言C++www.blog.wuhang-tinpack.com++C语言的魅力
编程语言C++read.share.wuhang-tinpack.com++C语言的魅力
编程语言C++xiangqintown.com++C语言的魅力
编程语言C++www.xiangqintown.com++C语言的魅力
编程语言C++www.share.xiangqintown.com++C语言的魅力
编程语言C++m.www.xiangqintown.com++C语言的魅力
编程语言C++m.share.xiangqintown.com++C语言的魅力
编程语言C++www.blog.xiangqintown.com++C语言的魅力
编程语言C++read.share.xiangqintown.com++C语言的魅力
编程语言C++youdangxian.com++C语言的魅力
编程语言C++www.youdangxian.com++C语言的魅力
编程语言C++www.share.youdangxian.com++C语言的魅力
编程语言C++m.www.youdangxian.com++C语言的魅力
编程语言C++m.share.youdangxian.com++C语言的魅力
编程语言C++www.blog.youdangxian.com++C语言的魅力
编程语言C++read.share.youdangxian.com++C语言的魅力
编程语言C++jinqiaozhuzao.comC语言的魅力
编程语言C++www.jinqiaozhuzao.com++C语言的魅力
编程语言C++www.share.jinqiaozhuzao.com++C语言的魅力
编程语言C++m.www.jinqiaozhuzao.com++C语言的魅力
编程语言C++m.share.jinqiaozhuzao.com++C语言的魅力
编程语言C++www.blog.jinqiaozhuzao.com++C语言的魅力
编程语言C++read.share.jinqiaozhuzao.com++C语言的魅力
编程语言C++exon-soft.com++C语言的魅力
编程语言C++www.exon-soft.com++C语言的魅力
编程语言C++www.share.exon-soft.com++C语言的魅力
编程语言C++m.www.exon-soft.com++C语言的魅力
编程语言C++m.share.exon-soft.com++C语言的魅力
编程语言C++www.blog.exon-soft.com++C语言的魅力
编程语言C++read.share.exon-soft.com++C语言的魅力
编程语言C++anonymouslodge.com++C语言的魅力
编程语言C++www.anonymouslodge.com++C语言的魅力
编程语言C++www.share.anonymouslodge.com++C语言的魅力
编程语言C++m.www.anonymouslodge.com++C语言的魅力
编程语言C++m.share.anonymouslodge.com++C语言的魅力
编程语言C++www.blog.anonymouslodge.com++C语言的魅力
编程语言C++read.share.anonymouslodge.com++C语言的魅力
编程语言C++zasw1688.com++C语言的魅力
编程语言C++www.zasw1688.com++C语言的魅力
编程语言C++www.share.zasw1688.com++C语言的魅力
编程语言C++m.www.zasw1688.com++C语言的魅力
编程语言C++m.share.zasw1688.com++C语言的魅力
编程语言C++www.blog.zasw1688.com++C语言的魅力
编程语言C++read.share.zasw1688.com++C语言的魅力
编程语言C++y7ds.com++C语言的魅力
编程语言C++www.y7ds.com++C语言的魅力
编程语言C++www.share.y7ds.com++C语言的魅力
编程语言C++m.www.y7ds.com++C语言的魅力
编程语言C++m.share.y7ds.com++C语言的魅力
编程语言C++www.blog.y7ds.com++C语言的魅力
编程语言C++read.share.y7ds.com++C语言的魅力
编程语言C++xuel5.com++C语言的魅力
编程语言C++www.xuel5.com++C语言的魅力
编程语言C++www.share.xuel5.com++C语言的魅力
编程语言C++m.www.xuel5.com++C语言的魅力
编程语言C++m.share.xuel5.com++C语言的魅力
编程语言C++www.blog.xuel5.com++C语言的魅力
编程语言C++read.share.xuel5.com++C语言的魅力
编程语言C++mdgykj.com++C语言的魅力
编程语言C++www.mdgykj.com++C语言的魅力
编程语言C++www.share.mdgykj.com++C语言的魅力
编程语言C++m.www.mdgykj.com++C语言的魅力
编程语言C++m.share.mdgykj.com++C语言的魅力
编程语言C++www.blog.mdgykj.com++C语言的魅力
编程语言C++read.share.mdgykj.com++C语言的魅力
编程语言C++xqfwb.com++C语言的魅力
编程语言C++www.xqfwb.com++C语言的魅力
编程语言C++www.share.xqfwb.com++C语言的魅力
编程语言C++m.www.xqfwb.com++C语言的魅力
编程语言C++m.share.xqfwb.com++C语言的魅力
编程语言C++www.blog.xqfwb.com++C语言的魅力
编程语言C++read.share.xqfwb.com++C语言的魅力
编程语言C++dongkesm.com++C语言的魅力
编程语言C++www.dongkesm.com++C语言的魅力
编程语言C++www.share.dongkesm.com++C语言的魅力
编程语言C++m.www.dongkesm.com++C语言的魅力
编程语言C++m.share.dongkesm.com++C语言的魅力
编程语言C++www.blog.dongkesm.com++C语言的魅力
编程语言C++read.share.dongkesm.com++C语言的魅力
编程语言C++hongtaili2023.com++C语言的魅力
编程语言C++www.hongtaili2023.com++C语言的魅力
编程语言C++www.share.hongtaili2023.com++C语言的魅力
编程语言C++m.www.hongtaili2023.com++C语言的魅力
编程语言C++m.share.hongtaili2023.com++C语言的魅力
编程语言C++www.blog.hongtaili2023.com++C语言的魅力
编程语言C++read.share.hongtaili2023.com++C语言的魅力
编程语言C++tangshineng.com++C语言的魅力
编程语言C++www.tangshineng.com++C语言的魅力
编程语言C++www.share.tangshineng.com++C语言的魅力
编程语言C++m.www.tangshineng.com++C语言的魅力
编程语言C++m.share.tangshineng.com++C语言的魅力
编程语言C++www.blog.tangshineng.com++C语言的魅力
编程语言C++read.share.tangshineng.com++C语言的魅力
编程语言C++leipotech.com++C语言的魅力
编程语言C++www.leipotech.com++C语言的魅力
编程语言C++www.share.leipotech.com++C语言的魅力
编程语言C++m.www.leipotech.com++C语言的魅力
编程语言C++m.share.leipotech.com++C语言的魅力
编程语言C++www.blog.leipotech.com++C语言的魅力
编程语言C++read.share.leipotech.com++C语言的魅力
编程语言C++kunheshanye.com++C语言的魅力
编程语言C++www.kunheshanye.com++C语言的魅力
编程语言C++www.share.kunheshanye.com++C语言的魅力
编程语言C++m.www.kunheshanye.com++C语言的魅力
编程语言C++m.share.kunheshanye.com++C语言的魅力
编程语言C++www.blog.kunheshanye.com++C语言的魅力
编程语言C++read.share.kunheshanye.com++C语言的魅力
 

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐