I've been playing around to see how my computer works under the hood. What I'm interested in is seeing is what happens on the stack inside a function. To do this I've written the following toy program:
#include <stdio.h>
void __cdecl Test1(char a, unsigned long long b, char c)
{
char c1;
unsigned long long b1;
char a1;
c1 = 'b';
b1 = 4;
a1 = 'r';
printf("%d %d - %d - %d %d Total: %d\n",
(long)&b1 - (long)&a1, (long)&c1 - (long)&b1,
(long)&a - (long)&c1,
(long)&b - (long)&a, (long)&c - (long)&b,
(long)&c - (long)&a1
);
};
struct TestStruct
{
char a;
unsigned long long b;
char c;
};
void __cdecl Test2(char a, unsigned long long b, char c)
{
TestStruct locals;
locals.a = 'b';
locals.b = 4;
locals.c = 'r';
printf("%d %d - %d - %d %d Total: %d\n",
(long)&locals.b - (long)&locals.a, (long)&locals.c - (long)&locals.b,
(long)&a - (long)&locals.c,
(long)&b - (long)&a, (long)&c - (long)&b,
(long)&c - (long)&locals.a
);
};
int main()
{
Test1('f', 0, 'o');
Test2('f', 0, 'o');
return 0;
}
And this spits out the following:
9 19 - 13 - 4 8 Total: 53
8 8 - 24 - 4 8 Total: 52
The function args are well behaved but as the calling convention is specified, I'd expect this. But the local variables are a bit wonky. My question is, why wouldn't these be the same? The second call seems to produce a more compact and better aligned stack.
Looking at the ASM is unenlightening (at least to me), as the variable addresses are still aliased there. So I guess this is really a question about the assembler itself allocates the stack to local variables.
I realise that any specific answer is likely to be platform specific. I'm more interested in a general explanation unless this quirk really is platform specific. For the record though, I'm compiling with VS2010 on a 64bit Intel machine.