Take a look at these two functions:
void function1() { int x; int y; int z; int *ret; } void function2() { char buffer1[4]; char buffer2[4]; char buffer3[4]; int *ret; }
If I break at function1()
in gdb
, and print the addresses of the variables, I get this:
(gdb) p &x $1 = (int *) 0xbffff380 (gdb) p &y $2 = (int *) 0xbffff384 (gdb) p &z $3 = (int *) 0xbffff388 (gdb) p &ret $4 = (int **) 0xbffff38c
If I do the same thing at function2()
, I get this:
(gdb) p &buffer1 $1 = (char (*)[4]) 0xbffff388 (gdb) p &buffer2 $2 = (char (*)[4]) 0xbffff384 (gdb) p &buffer3 $3 = (char (*)[4]) 0xbffff380 (gdb) p &ret $4 = (int **) 0xbffff38c
You'll notice that in both functions, ret
is stored closest to the top of the stack. In function1()
, it is followed by z
, y
, and finally x
. In function2()
, ret
is followed by buffer1
, then buffer2
and buffer3
. Why is the storage order changed? We're using the same amount of memory in both cases (4 byte int
s vs 4 byte char
arrays), so it can't be an issue of padding. What reasons could there be for this reordering, and furthermore, is it possible by looking at the C code to determine ahead of time how the local variables will be ordered?
Now I'm aware that the ANSI spec for C says nothing about the order that local variables are stored in and that the compiler is allowed to chose its own order, but I would imagine that the compiler has rules as to how it takes care of this, and explanations as to why those rules were made to be as they are.
For reference I'm using GCC 4.0.1 on Mac OS 10.5.7
The stack is used for dynamic memory allocation, and local variables are stored at the top of the stack in a stack frame.
Every time a function is called, the machine allocates some stack memory for it. When a new local variables is declared, more stack memory is allocated for that function to store the variable. Such allocations make the stack grow downwards.
For local variables, the memory they consume is on the stack. This means that they must have a fixed size known at compile time, so that when the function is called, the exact amount of memory needed is added to the stack by changing the value of the stack pointer.
Stack memory only contains local primitive variables and reference variables to objects in heap space. Objects stored in the heap are globally accessible whereas stack memory can't be accessed by other threads.
I've no idea why GCC organizes its stack the way it does (though I guess you could crack open its source or this paper and find out), but I can tell you how to guarantee the order of specific stack variables if for some reason you need to. Simply put them in a struct:
void function1() { struct { int x; int y; int z; int *ret; } locals; }
If my memory serves me correctly, spec guarantees that &ret > &z > &y > &x
. I left my K&R at work so I can't quote chapter and verse though.
So, I did some more experimenting and here's what I found. It seems to be based on whether or not each variable is an array. Given this input:
void f5() { int w; int x[1]; int *ret; int y; int z[1]; }
I end up with this in gdb:
(gdb) p &w $1 = (int *) 0xbffff4c4 (gdb) p &x $2 = (int (*)[1]) 0xbffff4c0 (gdb) p &ret $3 = (int **) 0xbffff4c8 (gdb) p &y $4 = (int *) 0xbffff4cc (gdb) p &z $5 = (int (*)[1]) 0xbffff4bc
In this case, int
s and pointers are dealt with first, last declared on the top of the stack and first declared closer to the bottom. Then arrays are handled, in the opposite direction, the earlier the declaration, the highest up on the stack. I'm sure there's a good reason for this. I wonder what it is.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With