我准备面试。
我的c程序是:
void foo(void)
{
int a;
printf("%d\n",a);
}
void bar(void)
{
int a=42;
}
void main(void)
{
bar();
foo();
}
我得到的输出为:42
但是怎么样?我认为这将是一些垃圾价值。如何应用执行堆栈或激活框架的概念?
请解释
由于
答案 0 :(得分:5)
a
未在函数foo
中初始化。打印未初始化的变量会调用未定义的行为
在这种情况下,您可能得到任何预期或意外结果。在我的编译器上,输出是
4203214
结果可能会因编译器与编译器而异,即使同一编译器的不同版本也会给您不同的结果
但是获得42
的可能原因之一是因为自动变量通常在执行堆栈上分配。在调用bar
之后,42
被放置在执行堆栈上。该值保持不受干扰。调用foo
时,可能读取a
的堆栈空间并打印42
。
尝试优化代码(使用-o
编译),您可能会为a
获得一些不同的值。
答案 1 :(得分:3)
对bar()
的调用将值42
放在堆栈上。调用foo()
时仍然存在。
bar()
和foo()
的堆叠帧可能相同或至少相似,因此a
中的foo()
保留值42
当然,这不能保证,并且是未定义的行为。但是,对于调试代码,通常需要一些理解,而不是像通常那样简单地解决这些问题。
如果您提高优化级别(至少在gcc中),您看到的行为将会改变。
答案 2 :(得分:1)
当您从bar()
致电main()
时,它会将a = 42
设置在堆栈上,从main()
执行的位置开始。当您从foo()
调用main()
时,它会打印a
的值,该值在此范围内也是从main()
执行的位置开始的一个int。
首先调用bar()
,您已在堆栈上设置数据,并且由于foo()
和bar()
具有相同的调用框架,bar()
的{{1}} }和a
的{{1}}最终位于相同的内存地址中。
正如其他答案所指出的那样,这是未定义的行为。在这种情况下,该值将持续存在于堆栈中并最终位于同一位置。