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

关于C18标准6.5节有效类型限制的澄清与疑问

C18标准有效类型规则与联合访问的未定义行为分析

先明确C18标准的核心规则

C18 §6.5.6(有效类型定义):
对象的有效类型是其声明类型(若对象有声明)。若通过无声明类型的左值访问对象存储值,则该左值的类型成为对象的有效类型。若通过字符类型左值访问,不改变有效类型。对于动态分配的对象,首次写操作的左值类型即为有效类型;若未被写入,可使用任何兼容类型。对于联合对象,当访问其某个成员时,该联合对象的有效类型即为当前被访问成员的类型。

C18 §6.5.7(对象存储访问规则):
对象的存储值只能通过以下类型之一的左值表达式访问:

  • 与对象有效类型兼容的类型;
  • 上述类型的限定版本;
  • 与有效类型对应的有符号/无符号类型;
  • 上述类型的限定版本;
  • 包含上述类型作为成员的聚合/联合类型(递归包含子聚合/子联合成员);
  • 字符类型。

第一个案例的未定义行为分析

给出的代码及调用上下文:

short g(int *p, short *q) {
  short z = *q; *p = 10; return z;
}

union int_or_short { int x; short y; } u = { .y = 3 };
int *p = &u.x;
short *q = &u.y;
return g(p, q);

内联函数体后逻辑更清晰:

union int_or_short { int x; short y; } u = { .y = 3 };
int *p = &u.x;
short *q = &u.y;
short z = *q; // 通过short类型左值访问联合对象u
*p = 10;      // 通过int类型左值写u的存储

违规原因:

  1. 执行short z = *q;时,通过short类型左值访问联合对象u,根据§6.5.6规则,u的有效类型被设置为short。
  2. *p = 10;是写操作,属于标准定义的“访问对象存储值”范畴(读、写操作都算访问)。此时p解引用后是int类型左值,而u当前有效类型是short——int与short不属于兼容类型,完全不符合§6.5.7的访问规则,因此触发未定义行为。

第二个案例为何合法?

对比代码:

union int_or_short { int x; short y; } u = { .y = 3 };
short z = u.y;
u.x = 10;

合法原因:

C标准明确允许联合的核心用途——通过任意成员复用同一块内存。当执行u.x = 10;时,这是直接通过联合对象访问其成员:

  • 根据§6.5.6规则,访问联合的x成员会自动将u的有效类型更新为int;
  • 这种访问方式属于§6.5.7中允许的“联合类型包含对应成员”的场景,完全符合有效类型规则,因此是合法的,不存在未定义行为。

核心疑问:*p=10与u.x=10的本质区别

  • *p=10:p是指向联合成员x的独立指针,此时联合对象的有效类型是short(此前通过y成员访问过)。这里是绕过联合对象的直接访问,用int类型左值访问有效类型为short的对象,违反访问规则。
  • u.x=10:直接通过联合对象访问成员,标准会自动更新联合的有效类型为当前成员的类型,且属于联合设计允许的内存复用场景,完全符合规则。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 07:37:38