以下代码生成y是答案,但我从未将42分配给y,怎么可能是42?
#include <stdio.h>
void doit2(void)
{
int x;
int y;
if (x == 42)
{
printf("x is the answer\n");
}
else if (y == 42)
{
printf("y is the answer\n");
}
else
{
printf("there is no answer\n");
}
}
void doit1(int a)
{
int b = a;
}
int main(void)
{
doit1(42);
doit2();
}
答案 0 :(得分:12)
这是由于调用函数的方式。调用doit1
时,参数a
(42)放在调用堆栈上,b
(也是42)就在它的正上方。当您退出doit1
并输入doit2
时,x
和y
位于同一位置a
且b
位于doit1
。由于两者都没有被初始化,所以它们只使用该点中已有的任何值 - 在您的情况下为42。当然,根据优化情况,这可能不会始终发生,但这是一个相当不错的选择。
维基百科在how the call stack works上有一篇不错的文章。
答案 1 :(得分:10)
将会有一些答案指出堆栈/寄存器/临时变量的问题,但我会指出,如果使用优化进行编译,则没有答案。
$ gcc -O3 42.c -o 42 $ ./42 there is no answer $ gcc -O2 42.c -o 42 $ ./42 there is no answer
此外,当你不优化时,答案似乎取决于你的编译器:
$ gcc 42.c -o 42 $ ./42 x is the answer $ tcc -run 42.c y is the answer
在GCC中,未经优化的 doit2导致此程序集:
doit2:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
cmpl $42, -4(%ebp)
jne .L2
movl $.LC0, (%esp)
call puts
jmp .L5
.L2:
cmpl $42, -8(%ebp)
jne .L4
movl $.LC1, (%esp)
call puts
jmp .L5
.L4:
movl $.LC2, (%esp)
call puts
.L5:
leave
ret
优化后,我们甚至不会与42比较:
doit2:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
movl $.LC2, (%esp)
call puts
leave
ret
答案 2 :(得分:1)
x和y的值是未定义的,它们恰好位于分配它们的位置。
在您的情况下,y变量要么分配在a
参数中的b
参数或doit1
变量所在的同一位置。这种情况发生在您使用的编译器中,具有您使用的特定设置。任何其他组合可能会产生不同的结果,因为有许多事情可以用不同的方式实现:
doit1
函数可以作为函数存在,也可以内联。doit1
函数的参数可以在堆栈中发送,也可以在寄存器中发送。b
中的变量doit1
可能存在与否。由于它从未使用过,编译器可以删除该语句。x
中的y
和doit2
变量中的任何一个都可以在堆栈或寄存器中以任意组合方式分配。