不同版本的 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++;
我已经从 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++;