结构体成员赋值时右值读取整个结构体是否属于未定义行为的技术问询
结构体成员赋值时右值读取整个结构体是否属于未定义行为的技术问询
先看一个非常标准的结构体定义:
struct foo { int a; int b; int crc; int c; };
以及对应的初始化代码:
s.a = 1; s.b = 2; s.c = 3; // 规范要求crc字段要基于整个结构体(且crc字段先设为0)计算得出 s.crc = 0; s.crc = crc32(&s, sizeof(s));
我的疑问集中在最后一行代码上。右边的crc32调用当然不会修改s本身,所以这和i = i++那种经典未定义行为场景不太一样,但我还是拿不准这在技术上算不算未定义行为,是不是必须用临时变量拆成两步写:
int crc = crc32(&s, sizeof(s)); s.crc = crc;
我脑补过一个有点极端的场景:编译器在调用crc32之前需要把某个寄存器的值暂存起来,它发现“反正s.crc马上就要被更新了”,于是不使用栈上的临时槽位,直接把s.crc当作暂存空间来用。相当于生成这样的汇编代码:
mov regX, s.crc call crc32() mov s.crc, regX mov regA, s.crc
查C99标准的话,有这样的规定:
C99 6.5.16.1.3:“如果要存储到对象中的值是从与第一个对象有任何存储重叠的另一个对象读取的,那么重叠必须完全重合,且两个对象的类型(含限定符)必须兼容;否则行为是未定义的。”
但这里要存储的值并不是直接从另一个对象读取的,而是通过读取整个结构体(包含要赋值的成员)计算出来的,这就让我拿不准了。
备注:内容来源于stack exchange,提问作者Villemoes
相关产品推荐
相关产品推荐

