So, someone posted a simple snippet on X yesterday:
#include <stdio.h>
int main()
{
int a, b, *p;
p = &a;
printf("%p == %p\n", &b, p + 1);
return 0;
}
And guess what — it printed the same address for &b
and p + 1
.
My colleague Bob immediately asked:
"Wait, isn’t x86 Linux stack supposed to grow downward? Why doesb
seem to be aftera
in memory then?"
Good question, Bob. This little puzzle confused me too at first. So here’s the story and the explanation.
Stack grows downward, right? Then why does this happen?
Yes, the stack grows downward on x86 — that means when you call a function, the stack pointer moves to lower addresses to allocate space.
But here’s the catch: the order of local variables inside a function’s stack frame isn’t dictated by the stack growth direction.
The compiler decides how to arrange local variables in memory. Usually, it just puts them in increasing memory order — so b
ends up at a higher address than a
, even though the stack overall grows downward.
What’s really going on with pointer arithmetic?
When you do p = &a;
and then p + 1
, that means “move the pointer by one int
size forward in memory,” so it points to the next int
after a
.
Since the compiler put b
right after a
in memory, p + 1
points exactly to b
.
- Note: Within a frame, variables are placed in increasing memory address order (usually).
- This is independent of the stack growth direction.
Why does the compiler arrange variables like that?
It’s mostly for convenience and optimization. The compiler doesn’t have to lay them out from high to low addresses just because the stack pointer goes down. It just lays out variables in some order that fits its internal rules.
So even though the stack grows down, the frame itself is like a little block of memory, and variables are placed inside that block in increasing addresses.
Bob, you were wrong because the compiler is free to lay out variables however it likes within the stack frame, and GCC tends to place locals in increasing address order, regardless of stack growth direction.
What you should NOT do
Don’t assume local variables are adjacent or laid out any specific way. Pointer arithmetic only safely works on arrays, not separate variables.
TL;DR
- The stack grows downward (stack pointer moves to lower addresses) on x86.
- Local variables inside a stack frame are laid out by the compiler, usually in increasing address order.
- So
&b == &a + 1
can happen even if the stack grows down. - Don’t rely on local variable layout assumptions — it’s compiler-dependent and unsafe.