我正在阅读the FreeBSD coding style并且非常喜欢它(因为我喜欢垂直紧凑的代码)。但是有这个:
初始化所有变量
你应该总是初始化变量。总是。每次。带有标志-W的gcc可以捕获未初始化变量的操作,但是 它也可能没有。理由
比你想象的更多的问题最终会追溯到未初始化的指针或变量。
如果变量没有合适的初始值,那么在没有值的情况下保留它是不是更好。这样编译器可能会在未初始化的情况下读取它。我不是在谈论T *p = NULL
,这是一个陷阱表示,可能(或可能不是)非常有用,而是int personal_number = 0 /* but 0 is a valid personal number!!*/
为了澄清,为了回应 abasu 的评论,我的示例是试图说明没有可用无效值时的情况。我问过question,并回答说使用不可能的值来标记错误或其他条件非常棒。但情况并非总是如此。例子很多:8位像素值,速度矢量等
“始终初始化变量”的一个有效替代方法,我可以看到:
//logical place for declarations
T a;
/*code, for example to set up the environment for evaluating a*/
a = fooForA();
/*more code*/
fooThatUsesA(a);
这样一来,如果忘记了初始化,就会出现警告并修复错误,删除警告。
答案 0 :(得分:4)
所有整数都是有效的个人号码吗?
如果没有,则使用无效值初始化personal_number
。
如果是,那么即使您没有自己初始化personal_number
,它仍然拥有一个有效的个人号码 - 但该值未知。所以无论如何将它初始化为0
- 你没有引入问题(之前的有效数字,之后的有效数字),唯一的区别是这个数字现在已为您所知。
当然,在这两种情况下,最好不要使用整数文字进行初始化,而是做类似的事情:
enum { INVALID_PERSONAL_NUMBER = -1 }
int personal_number = INVALID_PERSONAL_NUMBER;
答案 1 :(得分:2)
编译器通常不会捕获未初始化的读取变量。相反,他们可能会使用该信息来对其余代码进行假设以执行优化,可能会引入新的和更糟糕的错误:
int get_personal_number(const char *name)
{
int personal_number;
if (name != NULL) {
/* look up name in some array */
personal_number = ...
}
return personal_number;
}
优化编译器将推断 name
不能NULL
并取消检查。类似的问题也导致了安全漏洞;见例如http://blog.llvm.org/2011/05/what-every-c-programmer-should-know_14.html
相反,重写您的函数以在声明时初始化变量及其最终正确值;这可能需要编写许多小函数,使用三元表达式等,这通常是更好的风格。
答案 2 :(得分:1)
如果变量没有合适的初始值,那么在没有值的情况下保留它是不是更好。
在我看来是的。现代编译器非常擅长捕获未初始化的变量错误,并且clang静态分析器几乎完美无缺。让编译器捕获问题比放入会导致运行时问题的问题要好得多。例如,将指针初始化为NULL将禁止编译器警告,但是当您尝试取消引用它时,它不会停止核心转储。
但是,如果您使用的是现代编译器,那么您可能正在使用C99,这意味着您不需要声明变量,直到您知道它的合理值。这就是我要做的事。
答案 3 :(得分:0)
初始化变量总是很有用,并且是一种很好的编码实践。 这个例子可以理解:
未初始化的变量将包含一些垃圾值。如果你没有初始化它,那么你试图使用它。你可能得到一些不可预知的结果。 例如:
int test(void)
{
int a; //uninitialized variable
//You didn't initialize a
if(a > 10)
{
//Unpredicted result
}
else{}
return 0;
}
如果程序较大,这些类型的遗漏很常见,情况就会变得严峻。 因此,为了避免在调试时可能会耗费大量时间的愚蠢错误,应始终初始化变量