当前位置:  开发笔记 > 编程语言 > 正文

堆栈是向上还是向下增长?

如何解决《堆栈是向上还是向下增长?》经验,为你挑选了3个好方法。

我在c中有这段代码:

int q = 10;
int s = 5;
int a[3];

printf("Address of a: %d\n",    (int)a);
printf("Address of a[1]: %d\n", (int)&a[1]);
printf("Address of a[2]: %d\n", (int)&a[2]);
printf("Address of q: %d\n",    (int)&q);
printf("Address of s: %d\n",    (int)&s);

输出是:

Address of a: 2293584
Address of a[1]: 2293588
Address of a[2]: 2293592
Address of q: 2293612
Address of s: 2293608

所以,我看到,从那里a开始a[2],内存地址每个增加4个字节.但是,从qs,内存地址减少了4个字节.

我想知道两件事:

    堆栈是成长还是下降?(在这种情况下看起来对我来说都是)

    a[2]q内存地址之间发生了什么?为什么那里存在很大的记忆差异?(20个字节).

注意:这不是作业问题.我很好奇堆栈是如何工作的.谢谢你的帮助.



1> Ganesh Gopal..:

堆栈(成长或增长)的行为取决于应用程序二进制接口(ABI)以及如何组织调用堆栈(也称为激活记录).

在其整个生命周期中,程序必然会与其他程序(如OS)进行通信.ABI确定程序如何与另一个程序通信.

不同体系结构的堆栈可以以任何一种方式增长,但对于体系结构,它将是一致的.请检查此维基链接.但是,堆栈的增长是由该架构的ABI决定的.

例如,如果您使用MIPS ABI,则调用堆栈定义如下.

让我们考虑函数'fn1'调用'fn2'.现在'fn2'看到的堆栈帧如下:

direction of     |                                 |
  growth of      +---------------------------------+ 
   stack         | Parameters passed by fn1(caller)|
from higher addr.|                                 |
to lower addr.   | Direction of growth is opposite |
      |          |   to direction of stack growth  |
      |          +---------------------------------+ <-- SP on entry to fn2
      |          | Return address from fn2(callee) | 
      V          +---------------------------------+ 
                 | Callee saved registers being    | 
                 |   used in the callee function   | 
                 +---------------------------------+
                 | Local variables of fn2          |
                 |(Direction of growth of frame is |
                 | same as direction of growth of  |
                 |            stack)               |
                 +---------------------------------+ 
                 | Arguments to functions called   |
                 | by fn2                          |
                 +---------------------------------+ <- Current SP after stack 
                                                        frame is allocated

现在你可以看到堆栈向下增长.因此,如果变量被分配给函数的本地帧,则变量的地址实际上向下增长.编译器可以决定内存分配的变量顺序.(在你的情况下,它可以是'q'或's',它是第一次分配的堆栈内存.但是,通常编译器会根据变量声明的顺序堆栈内存分配).

但是在数组的情况下,分配只有单个指针,而需要分配的内存实际上是由单个指针指向的.内存需要与数组连续.因此,尽管堆栈向下增长,但对于数组,堆栈会增长.


此外,如果要检查堆栈是向上还是向下增长.在main函数中声明一个局部变量.打印变量的地址.从main调用另一个函数.在函数中声明一个局部变量.打印其地址.根据打印的地址,我们可以说堆栈增长或减少.

2> Crashworks..:

这实际上是两个问题.一个是关于当一个函数调用另一个函数时(当分配新帧时)堆栈增长的方式,另一个是关于如何在特定函数的框架中布置变量.

C标准都没有规定,但答案有点不同:

当分配新帧时,堆栈会以哪种方式增长 - 如果函数f()调用函数g(),那么f帧指针是否大于或小于g帧的指针? 这可以采用任何一种方式 - 它取决于特定的编译器和体系结构(查找"调用约定"),但它在给定平台内始终保持一致(有一些奇怪的例外,请参阅注释).向下是更常见的; 在x86,PowerPC,MIPS,SPARC,EE和Cell SPU中就是这种情况.

函数的局部变量如何在其堆栈框架内布局?这是未指明的,完全不可预测; 编译器可以自由安排其局部变量,但是它喜欢获得最有效的结果.


"它在给定平台内始终保持一致" - 不能保证.我见过一个没有虚拟内存的平台,其中堆栈是动态扩展的.新的堆栈块实际上是malloced,这意味着你将"向下"一个堆栈块一段时间,然后突然"侧向"到另一个块."侧身"可能意味着更大或更小的地址,完全取决于平局的运气.
有关第2项的其他详细信息 - 编译器可能能够确定变量永远不需要在内存中(在变量的生命周期内将其保存在寄存器中),和/或如果两个或多个变量的生命周期不存在t重叠,编译器可能决定对多个变量使用相同的内存.
我认为S/390(IBM zSeries)有一个ABI,其中调用帧被链接而不是在堆栈上增长.
在S/390上更正.呼叫是"BALR",分支和链接寄存器.返回值被放入寄存器而不是压入堆栈.返回函数是该寄存器内容的分支.随着堆栈变得更深,空间被分配在堆中并且它们被链接在一起.这就是MVS等同于"/ bin/true"的名称:"IEFBR14".第一个版本有一条指令:"BR 14",它分支到包含返回地址的寄存器14的内容.

3> R Samuel Kla..:

堆栈增长的方向是体系结构特定的.也就是说,我的理解是只有极少数硬件架构具有成长的堆栈.

堆栈增长的方向与单个对象的布局无关.因此,当堆栈可能长大时,数组将不会(即&array [n]将始终为<&array [n + 1]);

推荐阅读
小色米虫_524
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有