【发布时间】:2014-09-28 20:44:59
【问题描述】:
当我使用 Clang (-O3) 或 MSVC (/O2) 编译和运行此代码时...
#include <stdio.h>
#include <time.h>
static int const N = 0x8000;
int main()
{
clock_t const start = clock();
for (int i = 0; i < N; ++i)
{
int a[N]; // Never used outside of this block, but not optimized away
for (int j = 0; j < N; ++j)
{
++a[j]; // This is undefined behavior (due to possible
// signed integer overflow), but Clang doesn't see it
}
}
clock_t const finish = clock();
fprintf(stderr, "%u ms\n",
static_cast<unsigned int>((finish - start) * 1000 / CLOCKS_PER_SEC));
return 0;
}
...循环没有得到优化。
此外,既没有 Clang 3.6 也没有 Visual C++ 2013 也没有 GCC 4.8.1 告诉我该变量未初始化!
现在我意识到缺乏优化本身并不是一个错误,但考虑到现在编译器应该非常聪明,我发现这令人惊讶。这似乎是一段如此简单的代码,即使是十年前的活性分析技术也应该能够优化掉变量a,从而优化整个循环——更不用说增加变量已经未定义的事实行为。
然而只有 GCC 能够确定它是一个空操作,并且没有一个编译器告诉我这是一个未初始化的变量。
这是为什么?是什么阻止了简单的活性分析告诉编译器 a 未使用?此外,为什么编译器首先没有检测到a[j] 未初始化?为什么所有这些编译器中现有的未初始化变量检测器都无法捕捉到这个明显的错误?
【问题讨论】:
-
除了堆栈分配和内存中无意义位置的递增外,循环中没有副作用,除非使用关键字
volatile,否则编译器可以优化掉这些。clang没有看到执行循环没有任何用处,这真的很奇怪......如果你删除内部循环,编译器是否设法看到什么都不做? -
@Fors:您甚至不需要删除循环,只需将数组更改为单个变量,它就可以很好地优化。但在这种情况下,Clang 检测到变量未初始化,但 GCC 和 MSVC 似乎无法解决这个问题。
-
无论是否存在循环,只要类型是数组,就好像根本没有警告。无论编译器标志如何,此代码都会在没有任何警告的情况下编译:
int main(){ int x[1]; ++x[0];},在 Clang 和 g++ 上都 -
@Mehrdad 是的,我也看到了这个,确实很奇怪。另一方面,我不明白为什么未初始化的数组根本不会发出警告,即使在最简单的代码中也是如此。实际上我现在意识到对数组发出警告,但必须使用大于 0 的
-O优化。 -
我说的是
int main(){ int x[1]; ++x[0];}代码,它不会在-O0上发出警告,但会在-O1、-O2和-O3上发出警告。我使用 g++ (MacPorts gcc49 4.9-20140416_2) 4.9.0 20140416 (prerelease)。对于循环,只要未初始化在循环内,所有赌注都关闭,g++ 上没有更多警告,只有 clang。如果类型是数组,那么即使 clang 也不会发出警告。
标签: c++ visual-c++ gcc clang compiler-optimization