C代码:
int a;
printf("\n\t %d",a); // It'll print some garbage value;
那么这些垃圾值是如何在 C 的幕后分配给未初始化的变量的呢?
这是否意味着C首先将内存分配给变量'a',然后该内存位置的任何内容都变成'a'的值?或者是其他东西?
这是否意味着C首先将内存分配给变量'a',然后该内存位置的任何内容都变成'a'的值?
确切地!
基本上,C 不会做任何你不告诉它的事情。这既是它的强项,也是它的弱点。
这是否意味着C首先将内存分配给变量'a',然后该内存位置的任何内容都变成'a'的值?或者是其他东西?
正确的。值得一提的是,自动变量的“分配”int a
实际上是不存在的,因为这些变量存储在堆栈或 CPU 寄存器中。对于存储在堆栈中的变量,在调用函数时会执行“分配”,归结为将堆栈指针移动编译时计算的固定偏移量的指令(函数使用的所有局部变量的组合存储,四舍五入到正确对齐)。
分配给 CPU 寄存器的变量的初始值是寄存器以前的内容。由于这种差异(寄存器与内存),有时会发生在没有优化的情况下编译时正常工作的程序在打开优化的情况下编译时会开始中断。未初始化的变量,以前指向碰巧被零初始化的位置,现在包含以前使用相同寄存器的值。
最初内存有一些值,那些是未知值,也称为垃圾值,当我们声明一个变量时,根据我们在声明时指定的数据类型为变量保留一些内存,所以内存初始值是未知值,如果我们初始化其他一些值,那么我们的值将在那个内存位置。
int a
;
声明变量时,分配内存。但是这个变量没有被赋值,这意味着这个变量a
没有被初始化。如果这个变量a
只被声明而在程序中不再使用,则称为垃圾值。例如:
int a, b;
b=10;
printf("%d",b);
return 0;
在这里它只被声明但不再分配或初始化。所以这叫做垃圾值。
这是否意味着C首先将内存分配给变量'a',然后该内存位置的任何内容都变成'a'的值?
不,不是那个意思。
当一个对象未初始化时,C 标准不提供任何关于如何确定其值的计划。不仅如此,程序不需要表现得好像对象具有任何固定值。它可以变化,就好像为它保留的内存没有保持在任何固定状态,只是波动。
以下是关于此的特定 C 2018 规则:
malloc
, 7.22.3.5 2 用于分配的额外空间realloc
, 7.22.3.1 2 用于aligned_alloc
. 初始化其他对象,例如具有静态存储持续时间的对象。这意味着在每个实例中使用一个对象,C 标准对使用哪个值没有任何要求。它不需要与以前的使用相同。程序可能表现得好像它没有任何固定值。当它被多次使用时,程序可能会表现得好像每次都具有不同的值。例如,C 标准将允许printf("%d %d %d\n", a, a, a);
打印“34 -10200773 2147483204”。
发生这种情况的一种方式是,在尝试编译代码int a; printf("%d %d %d\n", a, a, a);
时,编译器无处可去a
,因为它从未被赋予任何固定值。因此,编译器不会生成无用的指令来将数据从未初始化的内存移动到传递参数的位置,而是不会生成任何内容。然后printf
被调用,传递参数的寄存器或堆栈位置包含它们之前的任何数据。这很可能是三个不同的值,它们会printf
打印出来。所以它看起来输出的观察者好像a
在printf("%d %d %d\n", a, a, a);
.
(此外,使用具有自动存储持续时间且尚未获取其地址的未初始化对象的值是明确未定义的行为,因为 6.3.2.1 2,关于将对象转换为其值,说“如果左值指定一个对象可以使用寄存器存储类声明的自动存储持续时间(从未获取其地址),并且该对象未初始化(未使用初始化程序声明并且在使用之前未对其进行分配),行为未定义。 ” 所以,当有一个对象满足这些条件时,使用它的值可以完全破坏程序;它可能不仅在不同的时间有不同的值,而且程序可能会中止,走一个与你预期不同的分支,而不是调用printf
当有一个printf
在源代码中,等等。)