为什么选择int; a = std :: max(a,x)不发出"未初始化"警告

时间:2017-02-08 16:00:36

标签: c++ compiler-warnings static-analysis

请考虑以下代码:

#include <vector>
#include <algorithm>
#include <iostream>

int main() {
    std::vector<int> v{{1, 2, 3}};
    int a;

    std::cout << a << std::endl;    // 1

    for (const int x : v) {
        a = std::max(a, x);         // 2
    }

    std::cout << a << std::endl;

    return 0;
}

随着现代编译器的发展,现在我们仍然密切关注程序员的愚蠢错误,他们会跟踪整合变量。但是,这个C ++代码会让他们感到困惑。到目前为止,我得到了以下结果:

                        (1)      (2)
g++ 5.3.1
clang++ 3.7              ✔
Solaris Studio 12.5      ✔

正如您所看到的,CLang和solstudio只能检测case(1)并忽略case(2),而g ++忽略了两者。在案例(2)中是否存在检测它的复杂情况?为什么g ++在这方面如此糟糕?

我使用的编译器选项:

$ g++-5 -std=c++11 -Wall -Wpedantic -pedantic -Wextra \
         -Wuninitialized -Wmaybe-uninitialized aisa.cpp
$ clang++ -std=c++11 -Wall -Wpedantic -pedantic -Wextra -Wuninitialized aisa.cpp
$ CC -std=c++11 -xprevise aisa.cpp

2 个答案:

答案 0 :(得分:12)

std::max的参数为const &,而<<的流式算子int的值为int。通过引用传递未初始化的对象是合法的:例如,如果函数只是获取其地址,则一切都很好。因此,将a传递给std::max时的警告很容易成为误报。

答案 1 :(得分:3)

首先:两个编译器只诊断第一次攻击,即他们只报告第一次未初始化使用a。因此,为了获得第二条警告,我们需要删除第一行:

#include <vector>
#include <algorithm>
#include <iostream>

int main() {
    std::vector<int> v{{1, 2, 3}};
    int a;

    for (const int x : v) {
        a = std::max(a, x);         // 2
    }

    std::cout << a << std::endl;

    return 0;

}

现在我们看到两个不相关的编译器怪癖: clang -Wconditional-uninitialized-Wall中不包含-Wextra。如果启用该功能,则执行会在std::cout处收到警告,因为它可能会打印未初始化的变量。

另一方面,

gcc 仅在启用优化程序时跟踪未初始化的变量,可能会加快编译构建的编译速度。使用-O2 -Wall时,gcc 6会在两种情况下都发出警告,但没有像第二种情况那样精确定位该位置。 (gcc&lt; = 5.3并没有像你观察到的那样对第二种情况发出警告,所以最近似乎已经实施了。)

所以TL; DR:你没有正确地调用你的编译器。