在阅读this主题后,我仍然感到有些困惑。是否定义了以下C ++表达式*d++ = ~(*d);
?是的,我知道像这样复杂的表达方式是丑陋的......我没有写出来。
当我将它与以下内容进行比较时,我发现生成的程序集略有不同:
*d = ~(*d);
d++;
汇编:
*d++ = ~(*d);
0x83384 LDR R3,[R0 <d>,4] <<diff
0x83388 ADD R1 <c>, R1 <c>, 1
0x8338c MVN R3, R3
0x83390 STR R3,[R0 <d>],4
VS
*d = ~(*d);
d++;
0x83384 LDR R3,[R0 <d>]
0x83388 ADD R1 <c>, R1 <c>, 1
0x8338c MVN R3, R3
0x83390 STR R3,[R0 <d>],4
谢谢!
答案 0 :(得分:11)
您的表达式有 未定义 (与未指定的相反)行为。汇编代码也可以发挥贝多芬的第9名,并且仍然符合标准。
从圣标,第5章,第4节:
在上一个和下一个序列点之间,标量对象的表达式评估最多只能修改一次存储值。
因此,代码格式不正确。我不知道符合标准的编译器是否需要来发出诊断信息,但是我已经被咬了很多次,我已经准备好打赌它不是。
有关更多详情,请参阅@Prasoon Saurav的精彩博览会there。
答案 1 :(得分:9)
*d++ = ~(*d);
在这个表达式中,没有任何对象有一个新值存储一次。 d + 1
的值作为增量运算符(d
)的副作用存储到d++
,并且在写入此增量之前d
指向的对象的值通过赋值运算符。
问题是d
被读取,不仅仅是为了确定要写回的值(即d + 1
),而是还要读取以确定要在右手中读取的地址侧子表达式~(*d)
。
这违反了ISO / IEC 14882:2003 5 [expr] / 4的第三句(为简洁省略了第一句):
[...]在前一个和下一个序列点之间,标量对象的表达式评估最多只能修改一次存储值。 此外,只能访问先前值以确定要存储的值。对于完整表达式的子表达式的每个允许排序,应满足本段的要求;否则行为未定义。
答案 2 :(得分:1)
你只是不知道什么时候评估++。我想你的编译器会在导致
的~(*d)
之前对其进行评估
*d = ~(*(d+1));
因此你的双重性。