Search code examples
cstack-pointer

Why does C not decrement the stack pointer if a variable leaves the scope?


#include <stdio.h>
void main() {
    {
        int x;
        printf("%p\n", &x);
    }
    {
        int x;
        printf("%p\n", &x);
    }
}

I would think running this that it would output the same thing twice. When it declares the first variable, it increments the stack pointer, but then leaves the scope, so it decrements it, and then just repeats the process the second time, so int x would occupy the same memory location on the stack both times.

But this isn't the case. The stack pointer is not decremented and int x in both cases occupy different locations in the stack. In fact, the first int x is still reachable even though its scope is gone.

#include <stdio.h>
void main() {
    {
        int x = 10;
        printf("%p\n", &x);
    }
    {
        int x = 25;
        printf("%p\n", &x);
    }
    {
        int x = 71;
        printf("%p\n", &x);

        int *p = &x;
        printf("%i %i %i\n", *(p + 2), *(p + 1), *p);
    }
}

Why is this? What am I misunderstanding?


Solution

  • The C standard does not even mention a stack. The compiler is free to optimize variables away when they are not needed. There is absolutely nothing in the C standard that implies that the printouts should be neither equal or not equal.

    On my computer, this manifests itself by giving different output depending on optimization level:

    $ gcc c.c
    
    /tmp$ ./a.out 
    0x7ffd8733c3ac
    0x7ffd8733c3a8
    
    /tmp$ gcc c.c -O3
    
    /tmp$ ./a.out 
    0x7fff4e91544c
    0x7fff4e91544c
    

    In fact, the first "int x" is still reachable even though its scope is gone.

    Accessing a variable that has gone out of scope causes undefined behavior, which means that anything can happen. This includes the case where the program works as intended.

    Here is the output from your second snippet with different optimizations:

    /tmp$ ./a.out 
    0x7ffd4df94864
    0x7ffd4df94860
    0x7ffd4df9485c
    10 25 71
    
    /tmp$ gcc c.c -O3
    
    /tmp$ ./a.out 
    0x7ffc30b4e44c
    0x7ffc30b4e44c
    0x7ffc30b4e44c
    0 0 71
    

    When you get different behavior depending on optimization level, that's an almost 100% sign that your program has something that is causing undefined behavior. There is a very, very small chance that you have encountered a bug in the compiler. And apart from those two reasons, I cannot think of anything else that could be the cause.