tags:

views:

152

answers:

3

The follow code generates y is the answer, but i've never assigned 42 to y, how could y be 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();
}
+10  A: 

There's going to be a few answers pointing out issues with stacks/registers/temporary variables, but I'll point out that if you compile with optimizations, there is no answer.

$ gcc -O3 42.c -o 42
$ ./42
there is no answer
$ gcc -O2 42.c -o 42
$ ./42
there is no answer

Moreover, when you don't optimize, the answer seems dependent on your compiler:

$ gcc 42.c -o 42
$ ./42
x is the answer
$ tcc -run 42.c
y is the answer

In GCC, the unoptimized doit2 results in this assembly:

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

When optimized, we don't even compare with 42:

doit2:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $8, %esp
        movl    $.LC2, (%esp)
        call    puts
        leave
        ret
Mark Rushakoff
+11  A: 

This is due to the way functions are called. When doit1 is called, the argument a (42) is put on the call stack, and b (also 42) is right above it. When you exit doit1 and enter doit2, x and y are in the same place a and b were in doit1. Since neither is initialized, they just use whatever value is already in that spot -- 42 in your case. Of course, depending on optimization, this might not always happen, but it's a pretty good bet that it will.

Wikipedia has a decent article on how the call stack works.

rlbond
+1  A: 

The values of x and y are undefined, they just are what happens to be in the location where they are allocated.

In your case the y variable is either allocated in the same spot where the a parameter or the b variable were in the doit1 method. This happens in the compiler that you used, with the specific settings that you used. Any other combination may give a different result, as there are many things that can be implemented in different ways:

  • The doit1 function could exist as a function or be inlined.
  • The parameter to the doit1 function can be sent either on the stack or in a register.
  • The variable b in doit1 could exist or not. As it's never used, the compiler could remove the statement.
  • Either of the x and y variables in doit2 could be allocated on the stack or in a register, in any combination.
Guffa