不同版本的 gcc 不同地编译相同的代码

Different versions of gcc differently compile the same code

我已经从 MS Visual Studio 切换到 gcc,目前我正在尝试通过 gcc 重新编译我在 VS 中编写的一些代码。现在我遇到了一些奇怪的事情。简单解释一下,考虑以下代码,但首先请注意,我已经知道这是一个非常糟糕的代码(这不是这里的重点)

#include <iostream>

int main()
{
    int i = 0,
        a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 },
        b[10] = { 6, 5, 4, 1, 3, 2, 9, 7, 10, 8 };

    while (i ^ 5)   a[i++] = a[i] + b[i];

    while (i ^ 10)  a[i++] = a[i] - b[i];

    for (int j = 0; j < 10; j++)
        std::cout << a[j] << ' ';
}

当我用 Visual Studio 编译它时,结果是:

7 7 7 5 8 4 -2 1 -1 2 

符合预期。使用 gcc v.4.3.6 我也得到相同的结果 (Live example).

但是当我切换到 gcc 5.3.0 时,结果是:

7 7 5 8 8 -2 1 -1 2 -4198061

在生成许多关于未定义行为的警告之后。

问题是,为什么 visual studio,即使在其最新版本中,也不关心代码质量和未定义的行为,为什么早期版本的 gcc 也这样做?最近版本的 gcc 发生了什么?

这行代码在我看来是未定义的行为:

a[i++] = a[i] + b[i];

这可能意味着:

a[i] = a[i] + b[i];
i++;

或:

a[i] = a[i + 1] + b[i + 1];
i++;

似乎前两个编译器使用第一个解释,而第三个编译器使用第二个解释。

'while (i ^ 5) a[i++]' - 我修改了两次,没有序列点,所以UB。

'Between evaluation of the left and right operands of the && (logical AND), || (logical OR) ' - 没有提到 XOR。

也许……

该主题在 C++11 标准的 §1.9/15(程序执行)中讨论:

Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced. [ Note: In an expression that is evaluated more than once during the execution of a program, unsequenced and indeterminately sequenced evaluations of its subexpressions need not be performed consistently in different evaluations. — end note ] The value computations of the operands of an operator are sequenced before the value computation of the result of the operator. If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object or a value computation using the value of the same scalar object, and they are not potentially concurrent (1.10), the behavior is undefined. ...

void g(int i, int* v) {
    i = v[i++];       // the behavior is undefined
    i = 7, i++, i++;  // i becomes 9
    i = i++ + 1;      // the behavior is undefined
}

未定义的行为意味着:任何事情都可能发生,程序可能会按照您的预期运行,或者某些事情(如您所说)"strange" 可能会发生。

另请参阅:"Sequence point" on Wikipedia

... depending on the order of expression evaluation, the increment may occur before, after, or interleaved with the assignment. ...

快速解决方法是更改​​

while (i ^ 5)   a[i++] = a[i] + b[i];

while (i ^ 5)   a[i] = a[i] + b[i], i++;