7

我刚刚阅读关于未定义行为和序列点的 SO C++ FAQ 并进行了一些实验。在下面的代码gcc-4.5.2中,仅在代码注释中提到的行中给了我一个警告,尽管前面的一行也显示了未定义的行为,不是吗?您不能说首先执行哪个加法操作数(因为+没有序列点)。为什么 gcc 在这一行也没有给我警告?

int i=0;
int j=0;

int foo(void) {
    i=1;
    return i;
}

int main(void) {
    i = i + foo(); 
    j = j + (j=1); //Here is a rightly warning
    return 0;
}

谢谢你的帮忙。

4

3 回答 3

17

i = i + foo(); 的行为 是未指定的,但不是未定义的。未定义意味着允许任何可能的行为,甚至中止程序。未指定意味着要么首先评估 i,要么先评估 foo()。是的,foo 写入同一个 i,但由于它发生在单独的语句中,因此在该存储之前和之后有一个序列点。

于 2011-11-26T10:24:03.603 回答
2

程序中的行i = i + foo();是未指定的,但不是未定义的。

编译器尝试在没有误报的情况下发出警告(每次编译器发出警告,程序员都应该修复一个缺陷),或者至少误报率非常低。这意味着作为交换,他们有相当多的假阴性。为了保持相同的理念,编译器通常不会对未指定的行为发出警告。

要获得有关您的程序的警告,您应该查看静态分析器,它们对警告更具攻击性,但代价是误报稍微多一些。静态分析器可以很好地决定警告未指定的行为。其中一些甚至警告已定义的行为,尽管已定义,但表明程序员可能感到困惑。

于 2011-11-26T11:39:55.160 回答
-6

人类可以看到调用 foo() 会改变 i,但对于计算机程序来说很难看到。它只是不是为了看到这一点而设计的。

于 2011-11-26T10:26:18.620 回答