You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于`&((struct mystruct *)0)->u.b`代码片段的技术问询

问题描述

我编写了如下代码:

struct mystruct {
  char a;
  union {
    char a[8];
    char b[16];
  } u;
};

void fuu(void)
{
  struct mystruct s;

  printf("%ld %ld\n", sizeof(s), &((struct mystruct *)0)->u.b);
}

其中&((struct mystruct *)0)->u.b这段代码令我困惑。我的理解是:首先将0转换为struct mystruct类型的指针(这一步无法理解),然后取出该指针指向的联合体成员u.b(我认为这是char数组b的起始指针),再取该指针的地址并打印。我最困惑的是将0转换为结构体指针这一步,能否详细解释这段代码的执行逻辑?


代码执行逻辑详解

这段代码是计算结构体成员u.b相对于结构体起始地址偏移量的经典C语言技巧,核心就是靠0地址转指针的操作实现,一步步拆解:

1. (struct mystruct *)0:把0转为结构体指针

这不是真的要访问地址0的内存(那样会直接触发崩溃),只是利用C语言的指针语义,让编译器把这个指针当成指向struct mystruct类型数据的"虚拟起始地址"——我们假定这个结构体的起始位置在地址0,目的是让编译器按照结构体的内存布局来计算成员的位置。整个过程是编译期完成的,不会产生实际的内存访问操作。

2. ((struct mystruct *)0)->u.b:定位到u.b的起始位置

编译器根据结构体的内存布局,算出从"虚拟起始地址0"到u.b数组第一个元素的位置偏移。这里注意:数组名u.b在表达式中会自动转为指向数组首元素的指针,也就是等价于&u.b[0]。

3. &((struct mystruct *)0)->u.b:得到偏移量的数值

这里看似是取指针的地址,但实际上,因为前面的指针是从地址0偏移而来的,这个"地址值"就是u.b相对于结构体起始地址的偏移量。编译器会直接把这个数值作为常量计算出来,运行时只是把它当作long类型打印,完全不会碰内存。

补充说明

  • 为什么不会崩溃?因为这段代码是编译期常量表达式,编译时就已经算出具体数值,运行时只是打印这个数值,没有任何内存访问行为。
  • 你可以用标准库的offsetof宏替代这段代码,效果完全一致:
    #include <stddef.h>
    // ...
    printf("%ld %ld\n", sizeof(s), offsetof(struct mystruct, u.b));
    
    offsetof宏的底层实现本质上就是你写的这段逻辑,只是做了更严谨的兼容性封装。

内容的提问来源于stack exchange,提问作者Moses

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 19:54:27