int i = 0, n[] = {7, 5, 3, 1};
for ( ; i<3; n[i++] = n[i]);
事实上,两个不同的编译器(Code Blocks和CppDroid)产生两个不同的值。事实证明5,在 Code Blocks 中,在 CppDroid -3中。那么正确答案是什么?其中一个编译器有问题,还是任务本身不正确?
int i = 0, n[] = {7, 5, 3, 1};
for ( ; i<3; n[i++] = n[i]);
事实上,两个不同的编译器(Code Blocks和CppDroid)产生两个不同的值。事实证明5,在 Code Blocks 中,在 CppDroid -3中。那么正确答案是什么?其中一个编译器有问题,还是任务本身不正确?
在我看来,标准并没有规定执行赋值时左侧表达式和右侧表达式的求值顺序(顺序由特定的编译器确定)。
对于 C++11,第 5.17 节:
由于计算的最终结果取决于计算操作数的顺序,因此会出现未定义的行为。
对于C++17的第 5.18 节,评估顺序已被更严格地定义:
因此,不应发生未定义的行为。而循环执行后,数组不会改变,所以
n[1]等于5。C++ 编译器有权为优化目的重新排序指令。
考虑表达式
如何解读?
第一个选项。
也就是说,例如,当
i == 0第二个选项
也就是说,在
i == 0因此,由于未定义一个操作中的求值顺序,因此编译器可以生成第一个代码和第二个代码。所以这里的正确答案是:
PS 顺便说一下,Code::Blocks不是编译器,而是一个没有自带编译器的开发环境。
程序中存在未定义的行为。根据C++标准(1.9程序执行)
标准中有一个类似的例子。
没有。
该片段
n[i++] = n[i]引发未定义的行为,因为均衡操作不是序列点。这意味着运算符可以自由选择首先评估哪个表达式:
n[i++]orn[i]。唯一的限制是在赋值时,两个片段都必须按值给出(分别是引用和数字)。未定义的行为源于编译器独立对待这两个部分的事实。因此,
i++从左侧和i从右侧看,它们似乎没有相互连接。post-increment read-modify-write不仅可以与read互换,而且它们还可以相互混合。关于为什么赋值不是序列点的问题已经在伟大的 StackOverflow 上被问到:
PS顺便说一下,这个问题
++i + ++i有着相同的根本原因。未定义的行为。使用密钥运行的 g++ 编译器
-Wall对此给出了合理的警告。示例(对程序稍作修改以打印中间结果):
如您所见
n[1] = 3,即 这个赋值运算符中的编译器(在这种情况下,这是最后一部分for(;;))获取当前值i,计算并存储目标地址,递增,i根据新值i选择源数据( )n[i]并将其复制到目标地址。