我读了这篇关于未定义行为的answer,其中我看到了以下声明:
++++++i; // UB, parsed as (++(++(++i)))
我认为这不是未定义的行为。我有一个疑问,它在C ++中真的是UB吗?如果是,那么如何?
另外,我制作了程序并使用g++ prog.cpp -Wall -Wextra -std=gnu++1z -pedantic
命令进行编译,它工作正常,没有任何警告。它给出了预期的输出。
#include <iostream>
using namespace std;
int main()
{
int i = 0;
cout<<++++++i<<endl;
}
答案 0 :(得分:37)
在C ++ 03中,它是未定义的行为。在C ++ 11中它不是。各种预增量之间没有序列点。如果i
是用户定义的类型,那么它将是明确定义的行为,因为那时会有一个函数调用(一个序列点)。
在C ++ 11中,序列点的概念被替换为之前/之后的序列。缺陷637(http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#637)提供了一个先前未定义的构造变得明确定义的示例(i = ++i + 1
)。
要理解为什么它不是未定义的行为,让我们看看我们需要的部分。 ++i
相当于i = i + 1
(除了i
只评估一次)。如果我们将i = i + 1
替换为inc
,++(i = i + 1)
将变为inc = inc + 1
。
[expr.ass]声明:
在所有情况下,赋值在右和左操作数的值计算之后,以及赋值表达式的值计算之前进行排序。
因此i = i + 1
中的赋值在inc
的值计算之前被排序;但是,inc = inc + 1
中的分配在inc
的值计算之后按排序。没有未定义的行为,因为分配是按顺序排列的。
答案 1 :(得分:9)
有时行为是未定义的,即使很难想象它会如何被错误处理。但是在C ++之前的11版本中,这是未定义的,因为同一个对象被多次修改而没有指向插入的序列。
可以想象一个编译器通过将所有修改合并到i
来“优化”代码。因此,每个增量都会增加原始值。但那不是重点。如果标准这样说,UB是UB。无论我们是否能够想象失败的方式都无关紧要。