未分配的变量具有值

use*_*466 1 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();
}
Run Code Online (Sandbox Code Playgroud)

rlb*_*ond 12

这是由于调用函数的方式.当doit1被调用时,参数a(42)被放置在调用堆栈上,和b(也42)正上方.当你退出doit1并进入doit2,x并且y在同一个地方a并且bdoit1.由于两者都没有被初始化,所以它们只使用该点中已有的任何值 - 在您的情况下为42.当然,取决于优化,这可能不会总是发生,但它是一个相当不错的选择.

维基百科有一篇关于调用栈如何工作的文章.


Mar*_*off 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
Run Code Online (Sandbox Code Playgroud)

优化后,我们甚至不会与42进行比较:

doit2:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $8, %esp
        movl    $.LC2, (%esp)
        call    puts
        leave
        ret
Run Code Online (Sandbox Code Playgroud)