未分配的变量具有值

时间:2009-09-26 20:31:08

标签: c

以下代码生成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();
}

3 个答案:

答案 0 :(得分:12)

这是由于调用函数的方式。调用doit1时,参数a(42)放在调用堆栈上,b(也是42)就在它的正上方。当您退出doit1并输入doit2时,xy位于同一位置ab位于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中的ydoit2变量中的任何一个都可以在堆栈或寄存器中以任意组合方式分配。