Clang 没有报告 C++ 中未初始化的变量?
Posted
技术标签:
【中文标题】Clang 没有报告 C++ 中未初始化的变量?【英文标题】:Clang not reporting uninitalized variables in C++? 【发布时间】:2014-03-19 21:53:36 【问题描述】:我了解局部变量在 C++ 中不会自动初始化,因此在使用它们之前,您应该始终为它们赋值。然而,至少在简单的情况下,编译器应该警告你以防你忘记它。我或多或少地依赖和参考this article。
鉴于此程序,我假设在将 x
发送到 std::cout
时会收到警告...
#include <iostream>
int main(int argc, const char * argv[])
int x;
std::cout << x;
return 0;
...但没有弹出警告。但是,如果我运行静态分析器,我会收到预期的警告:函数调用参数是一个未初始化的值。
我使用 Xcode 5.1 和 Apple LLVM 5.1 编译器进行编译和运行。我使用 Xcode 命令行项目模板 (C++) 中的标准构建设置,语言方言设置为 GNU99(用于 C)和 GNU++11(C++)。
未初始化变量选项设置为是(积极) (-Wconditional-uninitialized
)。切换到 Yes (-Wuninitialized
) 会引发警告:在此处使用变量“x”时未初始化。 问题第 1 部分: 为什么默认设置 (-Wconditional-uninitialized
) 不显示警告? Xcode 中的文档表明激进选项会发现更多问题:
您可以在正常的未初始化值检查或发现更多问题但检查更严格的更积极(保守)检查之间切换。
奇怪的是,当我运行程序时,该值总是设置为0
,所以由于某种原因,它似乎被初始化了。 问题第 2 部分:为什么会这样?
【问题讨论】:
“似乎已初始化”并不能保证它总是被初始化。 是的。我只是假设在 99% 的情况下都会得到完整的垃圾输出,并且想知道我的工具链/设置的任何部分是否确实确保它被初始化? 刚刚发现这一点澄清了第二点:为了复杂的问题找到未初始化的变量,在调试器中运行程序时声明的变量通常被归零。这意味着您的程序每次在调试器中运行时都可以正常运行,但在发布模式下会间歇性崩溃! (Source)。一旦我切换到发布版本,“预期的”垃圾值就会显示出来...... 【参考方案1】:-
为什么没有警告?
在我的系统上使用clang
和-Wall
会正确警告错误。显然,默认设置不包括-Wall
(可能是为了避免使用在引入某些警告之前编写的正确代码生成警告)。
一般来说,如果您依赖编译器来帮助您进行草率的编程,您将会遇到麻烦。在没有仔细考虑的情况下输入代码并希望编译器会告诉你所有错误在任何语言中都是不好的,但对于 C++ 来说却是真正的彻底灾难。 C++ 的主要理念就是程序员不会犯任何错误,所以不要犯错误;-)
仔细考虑,如果可以的话,请始终与-Wall
合作。
-
为什么要初始化?
显然,您还没有理解“未定义行为”的含义。这并不意味着程序崩溃,也不意味着它会做任何有趣的事情。这意味着它可以做任何事情,通常程序会做任何会在未来给你带来最多问题的事情。
通常这种最危险的行为是让它看起来好像一切都很好(例如,您的变量确实已初始化)。错误值只会在您将该代码投入生产或仅当您向广大观众展示您的程序运行时才会显示。到那时,价值会有所不同,你的公开车祸视频会在 youtube 上疯传,你的妻子会换门锁,甚至你的父母也不会接你的电话。
只需初始化你的变量;更好:-)
【讨论】:
-Wall
确实可以完成这项工作。澄清一下:我并不是要质疑初始化变量的必要性,我只是不明白为什么默认编译器设置没有报告问题。感谢您的帮助和解释。【参考方案2】:
打开-Wall
是必要的,但足以保证我们的代码安全。
例如下面的代码,在MacOS的g++下(是clang)会打印出0,但肯定是UB:
#include <stdio.h>
#include <iostream>
using namespace std;
class Blob
public:
int age;
void hello() printf("hello\n");
;
int main()
Blob a;
//a.hello();
cout << a.age << endl;
return 0;
【讨论】:
我在使用clang++
13.0.0 的 Linux 上得到了相同的行为。 g++
11.1.0 会正确报告问题。以上是关于Clang 没有报告 C++ 中未初始化的变量?的主要内容,如果未能解决你的问题,请参考以下文章