为什么编译器不强制执行排序规则?

时间:2016-02-17 17:50:23

标签: c++ compiler-errors undefined-behavior

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

似乎在所有这些情况下,标准明确表示它是未定义的行为,因此它可以很容易地说“程序形成不良”,这通常会导致硬诊断。

3 个答案:

答案 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等)在计算上很难。这似乎会影响前一个问题。