2011-11-27 89 views
20

在C中,初始化一个变量到它自己的值是否合理?如果是的话,为了什么?初始化一个变量到它自己的未定义值

请允许我详细说明。在Git源文件中,有一些将变量初始化为自己的未定义值的示例,如transport.cwt-status.c中所示。我从这些声明中删除了任务并运行测试。看到没有回归,我认为这些任务是多余的。

另一方面,我用GCC 4.6和Clang 2.9做了一些简单的测试。

#include <stdio.h> 
int main() { 
    printf("print to increase probability of registers being non-zero\n"); 
    int status = status; 
    return printf("%i\n", status); 
} 

-Wall -std=c99和各种-O水平打印编译没有警告,并表明status == 0。具有非零优化级别的Clang虽然会打印一些垃圾值。这让我推断这些表达式的结果是不确定的。

我可以想象,这样的赋值可以抑制未初始化的变量警告,但从Git获取的示例并非如此。删除作业不会引入任何警告。

这样的任务是一个未定义的行为?如果不是,你用它们做什么?


我建议在Git邮件列表上进行更改。 Here's what I've learned

+0

也许git中的例子不会为* your *系统禁止未初始化的变量警告,而是在其他开发人员经常使用的系统上禁止该警告。使用GCC,未初始化的变量警告受优化标志影响,并且Clang生成一组完全不同的警告,即使它是GCC的“插入式替代品”。 –

+1

我会初始化这些变量为0(或-1),而不是完全放弃初始化。有人为了某个目的添加了代码;即使我发现使用奇怪的机制,我也可以尊重目的。 –

+1

@JonathanLeffler,不仅奇怪,在陷阱表示的平台上会产生未定义的行为。 –

回答

11

这将编译,因为标准C99§6.2.1/ 7说:

任何标识符不是结构,联合或枚举标记“具有范围,只是在其声明完成后开始“。声明符后面跟着初始值设定项。

然而,status值是不定。你不能依赖它被初始化为有意义的东西。

它是如何工作的?
int status为堆栈中存在的变量创建一个空间(本地存储),然后进一步读取该空间以执行status = statusstatus可能会初始化为存在于堆栈帧中的任何值。

如何防范这种自我初始化?
GCC提供特定设置来检测自己的初始化,并报告为错误:

-Werror =未初始化-Winit自

为什么在此代码中使用?
我能想到它是在该程序代码中使用的唯一原因是为了抑制未使用变量警告为前:在transport.c,如果控制从来没有while循环中去,然后在控制流动cmp将未使用的和编译器必须为其生成警告。同样的场景似乎是在wt-status.c

+2

我认为这个想法并不是要压制'未使用的变量'警告(你可以通过删除未使用的变量来做到这一点),而是'(有时)在初始化之前使用'警告。这是一个小细节 - 它不会改变答案主要部分的有效性。 –

+0

@JonathanLeffler:你的评论很有用。我在回答中弄错了这一点。 –

1

对我来说,这种自分配初始化的唯一原因是为了避免警告。

对于你的transport.c,我甚至不明白它为什么有用。我会留下cmp未初始化。

我自己的习惯(至少在C中)是初始化所有变量,通常为0.编译器将优化不需要的初始化,并且初始化所有变量使调试更容易。

存在这样的情况,当我想一个变量保持未初始化,而我可能会自己分配它:随机种子:

unsigned myseed = myseed; 
srand(myseed); 
+0

但是有没有任何运行时分析工具可以注意到,当它仍然保存未初始化的字节时,会读取“cmp”?逻辑应该在'while'中读入'if'前强制'cmp'分配一些东西,所以你希望编译器“闭嘴,因为人知道他在做什么”,但是'int cmp = 0'会击败运行时分析并可能隐藏错误。 –

+0

你的意思是*编译时*不*运行时*分析?但我不明白你的意见。 –

+0

'int cmp = cmp'可能足以欺骗编译器认为'cmp'总是在读取之前被分配,所以编译时警告将被抑制。但是,如果你在运行时观察字节,那么'int cmp = cmp'仍然会让'cmp'满了垃圾,直到'while'循环的条件初始化为止。所以,如果逻辑有缺陷,'if'可以读取'cmp'而不用'while'分配一个值,那么当使用'int cmp = cmp'时可以检测到这个值。使用'int cmp = 0'会抑制两种可能的警告。 –

1

在MacOS X 10.7.2,我试过了这个例子 - 与结果显示...

$ cat x3.c 
#include <stdio.h> 

int status = -7; 

int main() 
{ 
    printf("status = %d\n", status); 
    int status = status; 
    printf("status = %d\n", status); 
    return 0; 
} 
$ make x3 
gcc -O -std=c99 -Wall -Wextra x3.c -o x3 
$ ./x3 
status = -7 
status = 1787486824 
$ 

其中main()当地status已使用printf()所以自初始化拷贝垃圾各地的栈空间。

0

status可变我觉得status = status不会改变的status值(比int status;)。我认为这是用来抑制unused variable的警告。