不同版本的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示例)。
但当我切换到gcc 5.3.0时,结果是:
7 7 5 8 8 -2 1 -1 2 -4198061
在生成许多关于未定义行为的警告之后。
问题是,为什么visualstudio,即使是在其最新版本中,也不关心代码的质量和未定义的行为,以及为什么早期版本的gcc也这样做?最近版本的gcc发生了什么?
本主题在C++11标准的§1.9/15(程序执行)中进行了讨论:
除非另有说明,否则单独运算符的操作数和单独表达式的子表达式的求值都是无序列的。[注意:在执行过程中多次求值的表达式中对于一个程序,其子表达式的未排序和不确定排序的求值不需要在不同的求值中一致执行。——尾注]在运算符的结果的值计算之前对运算符进行排序。如果标量对象上的副作用相对于同一标量对象上另一个副作用或值计算未排序使用相同标量对象的值,并且它们不可能并发(1.10),行为未定义。。。
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 }
未定义的行为意味着:任何事情都可能发生,程序可能会按照你的预期运行,或者可能会发生"奇怪"的事情。
另请参阅:维基百科上的"序列点":
根据表达式求值的顺序,增量可能发生在赋值之前、之后或与赋值交错。。。
一个快速的解决办法是改变
while (i ^ 5) a[i++] = a[i] + b[i];
至
while (i ^ 5) a[i] = a[i] + b[i], i++;
这行代码在我看来是未定义的行为:
a[i++] = a[i] + b[i];
这可能意味着:
a[i] = a[i] + b[i];
i++;
或者:
a[i] = a[i + 1] + b[i + 1];
i++;
第一个编译器使用第一种解释,而第三个编译器使用第二种解释。
'当(i^5)a[i++]'-i修改了两次时,没有序列点,所以UB。
'在对&;(逻辑AND),||(逻辑OR)'—未提及XOR。
也许。。。。。。。
- 如何修复sfml c++代码编译错误
- 尝试用java代码编译和运行c++代码
- 此代码编译良好,但文件未创建?请指出错误
- 为什么我的 BaseClass:Method 代码编译(带有单冒号)?
- 代码编译没有任何输出,入门程序
- 通过Python Distutils(用于Python C扩展)使用可重定位的设备代码编译CUDA代码
- 代码编译但不起作用!cmd窗口只是理想和理想,但什么也没发生
- 无法使用 g++ 使用C++代码编译 C 库
- 如何在Ubuntu中使用Visual Studio代码编译C++代码
- 推力+提升代码编译错误
- C++代码编译,但在 Zorin OS 上运行时显示错误
- 如何在使用模板时将 CPP 代码编译到库文件中
- 是否可以将Visual Studio 2017将C 代码编译到EXE以外的文件类型中
- 使用 Visual Studio for C++ 代码编译错误
- 使用 Android Studio 使用本机代码编译 apk 时,如何在链接处删除 libgnustl_static.
- 使用 Emscripten 将 OpenCV 代码编译C++ Javascript
- 将C 代码编译到独立应用程序.App
- 为什么此代码编译 (C++11) 而没有类型不匹配错误
- 重用编译器前端的结果,以加快多个配置/平台的C++代码编译
- 如何将C++11代码编译为网络汇编