C语言函数return与赋值的语义差异及标准示例UB问题咨询
问题解释
触发UB的直接赋值场景
你提到的「直接赋值」指将示例中的函数调用替换为直接读取另一个union成员的写法:
// 该写法触发UB g.u2.f3 = g.u1.f2;
直接赋值触发UB的核心原因
- 首先union内的两个结构体
u1、u2没有符合标准要求的公共初始序列:u1的首成员是int f1,u2的首成员是struct s f3,二者类型完全不匹配,不满足C标准对union共享公共前缀的成员互访豁免条款。 - 两个赋值操作数对应的存储区域完全重叠:
u1.f2在union内的偏移是int类型的大小,u2.f3在union内的偏移是0,二者的存储范围完全重合,属于对同一块存储通过两个不兼容的类型别名同时进行读、写操作,违反严格别名规则,因此属于未定义行为。 - 补充:C标准没有规定赋值操作左右操作数的求值顺序,对
g.u1.f2的读和对g.u2.f3的写是未序列的,可能出现写操作提前覆盖尚未读完的存储区域的情况,进一步加剧了行为的不确定性。
函数返回写法合法的原因
- 函数
f执行return g.u1.f2时,会先完整读取g.u1.f2的值,将其拷贝到与返回类型struct s对应的独立临时对象中,此时对uniong的读取操作已经完全结束,临时对象的存储与uniong完全无关。 - 后续执行
g.u2.f3 = f()时,仅将独立临时对象的完整值写入g.u2.f3,不存在对uniong的同时读写,且写入操作会合法切换union的活跃成员为u2,全程没有违反标准规则。
标准规定不存在矛盾的原因
你引用的规定:
如果表达式的类型与所在函数的返回类型不同,该值会被转换,效果等同于对具有该函数返回类型的对象执行赋值操作。
这条规定仅约束return语句中的值类型转换语义,和存储访问时序、别名规则没有任何关系:它只是说明return 表达式中,将表达式结果转换为返回类型的规则,和返回类型对象 = 表达式的转换规则完全一致,并没有声明return+赋值的完整流程和直接赋值的存储访问逻辑等价,因此不存在矛盾。
内容的提问来源于stack exchange,提问作者Some Name
相关产品推荐
相关产品推荐

