【发布时间】:2010-08-11 09:25:58
【问题描述】:
如果我们在 C 编程中将变量声明为整数而不定义值,那么 printf 会从缓冲区打印一些垃圾值。有什么方法可以防止打印垃圾值吗?
我想检查是否可以在编译时完成?如果可能的话?
【问题讨论】:
标签: c programming-languages default-value compile-time garbage
如果我们在 C 编程中将变量声明为整数而不定义值,那么 printf 会从缓冲区打印一些垃圾值。有什么方法可以防止打印垃圾值吗?
我想检查是否可以在编译时完成?如果可能的话?
【问题讨论】:
标签: c programming-languages default-value compile-time garbage
是的。初始化变量。
【讨论】:
-O -Wall 传递给gcc,然后它会警告未初始化变量等常见错误。另见stackoverflow.com/questions/3375697/useful-gcc-flags-for-c
维基百科是这样说的:
在计算中,未初始化的变量是 已声明但未设置为确定的 使用前的已知值。它会 有一定的价值,但不是 可预见的一个。因此它是一个 编程错误和一个共同的来源 软件中的错误数
所以将其初始化为默认值。
【讨论】:
如果您要定义局部变量,则不需要。编译器不会为您初始化它们。堆栈的增长和收缩取决于被调用的函数及其局部变量。编译器在每次函数调用时清除所有内存是没有意义的。
但是,如果将全局变量放在.bss 中,则它们的初始值可以为 0,这是缩小程序大小的优化。
【讨论】:
在编译时,大多数编译器(例如 GNU 编译器)可以识别未初始化变量的使用位置。但是,您可能需要为 GNU 编译器设置标志,例如 -Wall。
变量的值在此处已经,尽管它可以是任何值。即它是变量的“初始”状态。
因此,你必须初始化变量以避免垃圾。
当变量x 被声明时,它已经分配了一个段给这个变量名引用的内存&x。未初始化的值和变量已经放置在内存地址中。
假设您初始化了一个 int 类型的变量 v。它被分配到一个内存地址,即 int * 类型的 &v。因此,地址&v 将被放置到内存中一个未使用的开放位置。
在 main 函数中考虑这段代码:
int x;
// A number of bytes (in this case, sizeof(int), usually 4 B) already allocated
// starting at a memory location &x.
printf("Value at address %p: %d", &x, x);
// Value at &x may be any int, which is unpredictable
编译此代码时,出现此警告消息,其中SOME_DIRECTORY 是任意目录:
SOME_DIRECTORY>gcc -Wall -g sampleprogram.c -o sampleprogram
sampleprogram.c: In function 'main':
sampleprogram.c:8:5: warning: 'x' is used uninitialized in this function [-Wuninitialized]
printf("Value at address %p: %d", &x, x);
内存的起始值,就像电路一样,是不可预测的。不管你的价值为什么是随机垃圾。这也是未定义行为的一种形式,这意味着C编译器的国际标准没有设置任何要求,因此任何事情都可能发生。这是一个非常糟糕的错误,可能会导致多个难以追踪的错误和故障。
【讨论】:
您当然希望在编译时包含所有警告和调试信息:gcc -Wall -Wextra -g 和 GCC。那么你很可能会收到警告,你应该改进你的代码以得到任何警告。
当然,你应该初始化你的变量。顺便说一句,这样的初始化代码很短,并且运行得非常快。在某些情况下(例如-O1)gcc 能够优化(使用as-if rule)并删除无用的初始化。因此,根据经验,不要害怕“无用”的初始化。
您应该养成初始化大多数变量的习惯(很少有例外,例如某些PRNG 的种子),实际上是所有变量。在少数情况下,如果您不是故意初始化变量并希望它保留一些垃圾值,请在注释中记录(但不要指望垃圾真的是随机的;实际上它仍然可能始终相同)。
阅读有关undefined behavior 的更多信息。成为UB的scared。
请记住,变量是源代码中的名称。变量在运行时不存在(只有位置存在)。它们可以被编译器删除,它们有时可能位于call stack 调用框架的某个插槽中,它们可以进入某个寄存器,等等...
【讨论】: