2014-03-07 96 views
6

我想弄清楚地址如何分配给位于堆栈上的变量。我跑到下面的小程序:意外的地址输出

int main() 
{ 
    long a; 
    int b; 
    int c; 

    printf("&a = %p\n", &a); 
    printf("&b = %p\n", &b); 
    printf("&c = %p\n", &c); 
} 

我的预期是(考虑地址正在下降)输出:

&a = 0x7fff6e1acb88 
&b = 0x7fff6e1acb80 
&c = 0x7fff6e1acb7c 

而是我的了:

&a = 0x7fff6e1acb88 
&b = 0x7fff6e1acb80 
&c = 0x7fff6e1acb84 

怎么来的c变量位于ab变量之间?变量不会在声明时放在堆栈上吗?

我试图从long更换的a类型int,我得到这个:

&a = 0x7fff48466a74 
&b = 0x7fff48466a78 
&c = 0x7fff48466a7c 

在这里,我不明白为什么是往上走的地址,而他们以前下降了?

我编译的程序使用gcc version 4.7.2 (Ubuntu/Linaro 4.7.2-11precise2),如果这有什么帮助。

回答

9

当变量被声明时变量没有放在栈上吗?

为什么地址往上走,而他们以前下降了?

他们可能会上升,但他们不需要。

编译器可以自由地重新设置它认为合适的局部变量的顺序,或者甚至可以删除或添加一些局部变量。

5

变量不一定按照声明的顺序放在栈上。你无法预测在哪里他们会 - 他们可以以任何顺序。正如glglgl在评论中指出的那样,他们甚至不必在堆栈中,只需将其保存在寄存器中即可。

+5

他们甚至不必在堆栈中。如果你不查询他们的地址,他们通常只在寄存器中。 – glglgl

+0

正确;好点子。 –

5

即使堆栈指针在给定的CPU上向下计数,程序将使用stack frames。如何在堆栈帧内分配某个参数是实现定义的。

另请注意,某些CPU具有递增计数堆栈指针。

另请注意,局部变量不一定在堆栈上分配。更经常地,它们被分配在CPU寄存器中。但是当你获取一个变量的地址时,你需要强制编译器将它分配给堆栈,因为寄存器没有地址。

1

Agreeing with @Lundin您无法打印这些最有可能坐在的寄存器的地址。您可以做的最好的事情是如何转储目标代码并调查在创建更多本地变量时会发生什么然后是保存它们的寄存器的数量。那是当你看到堆栈活动时(在反汇编中)。

$ gcc -c main.c -o main.o 
$ objdump -D main.o > main.dump 
1

它取决于编译器。 比如我为了与“4.8.1 GNU GCC版本”和编译器分配所有语言环境变量的测试代码:

&a = 0x7fffe265d118 
&b = 0x7fffe265d114 
&c = 0x7fffe265d110 
2

堆栈增长的方向取决于结构。在x86上,堆栈增长减少(从较高地址到较低地址)。如何将变量放入堆栈还取决于操作系统的应用程序二进制接口(ABI)以及编译器如何遵循ABI约定。但是,编译器不一定总是遵循ABI约定。