int n6 = n1 + ++n1;
之类的语句是未定义的行为,因为它们违反了排序规则。但如果它们违反了序列规则,为什么编译器不会给出一个硬错误呢?其他例子:
i = ++i + i++; // undefined behavior
i = i++ + 1; // undefined behavior (but i = ++i + 1; is well-defined)
f(++i, ++i); // undefined behavior
f(i = -1, i = -1); // undefined behavior
似乎在所有这些情况下,标准明确表示它是未定义的行为,因此它可以很容易地说“程序形成不良”,这通常会导致硬诊断。
答案 0 :(得分:4)
因为在一般情况下编译器很难在此处生成硬诊断。你已经展示了一个非常人为和明显的例子,但现实通常比这更复杂。只是说“不要这样做,并且编译器也不必告诉你它”也更容易。
答案 1 :(得分:2)
在一般情况下,很难检测到任意表达是否违反了排序规则。
int f(int *pa, int *pb) {
return ++*pa + ++*pb;
}
根据输入值,除了排序之外,它可以具有UB,例如考虑f(0, 0)
,但在仅考虑排序时,是否已定义行为?
没有足够的信息来回答这个问题。仅在pa == pb
时才违反排序规则。没有什么可以排除这一点,但同样地,没有任何迹象表明任何代码都会这样称呼它。
如果我们不能说,编译器也不能告诉你。因此,它不能形成错误,只能是未定义的,并且任何诊断都会被视为执行质量问题。
事实上,它在运行时未定义,而不是格式错误,因此有另一个结果:它意味着如果代码被执行它只是一个问题。我在评论中举了一个例子:
int main() { }
void f(int i) { ++i + ++i; }
函数f
具有未定义的行为,但整个程序没有,因为函数f
从未被调用过。因为C ++标准中没有也不可能有任何规则禁止这样做,即使是简单的情况,也不允许编译器发出错误消息。
但是,编译器总是被允许为任何代码发出警告(或任何其他非致命诊断),因此有用的编译器会尝试检测到这一点并让您知道您做错了什么。
答案 2 :(得分:1)
-Werror=sequence-point
检测并发出您正在谈论的行为的编译错误,但在一般情况下会产生误报。
我不知道编写符合此标志的一般实用程序是多么容易(可能很难以使其成为语言要求)。
我也不知道在什么意义上验证序列点的有效性(不可判断,NP-hard等)在计算上很难。这似乎会影响前一个问题。