【问题标题】:How the local variable stored in stack局部变量如何存储在堆栈中
【发布时间】:2018-05-25 16:45:48
【问题描述】:

对于程序来说,局部变量是在堆栈中定义和分配的,但是,我只是想知道局部变量的定义顺序与使用它的顺序不一样。 例如,在main函数中,定义了int a b c,如前所述,a b c是在栈中分配的,也就是说如果变量a位于栈底,但是当变量先被使用时,如何将a从栈中弹出呢? 还是 ebp 指向所有变量的存储位置?

【问题讨论】:

  • 存储在堆栈中的局部变量在方法返回之前不会从堆栈中“弹出”。堆栈和其他所有东西一样是内存,压入堆栈的是特定大小的保留区域,变量只存在于这个空间中,但它们只是内存访问,当方法返回时,整个内存区域都会被删除.
  • 将堆栈想象成一叠文件。当一个方法被调用时,一张新的纸被放在堆栈的顶部,并且在这张纸上该方法的所有局部变量都被记下。当方法返回时,我们删除整个工作表。只要方法还在调用栈上,纸就还在。在此方法中是否不再实际使用变量并不重要。尽管这可能是一种优化,以在方法执行时减少堆栈大小,但我不确定我是否听说过执行此操作的编译器/运行时。
  • 请记住,这整个事情通常被认为是低级的,大多数开发人员永远不需要知道它的实际细节。所以我的问题是,你为什么需要知道?您是否有需要解决的问题,或者您只是在寻找要学习的东西?
  • @LasseVågsætherKarlsen:纸叠类比是一个很好的类比。您为什么不将您的 cmets 转换为答案?
  • @LasseVågsætherKarlsen 您的第一条评论确实是一个很好的答案——把它变成一个答案!

标签: c linux stack


【解决方案1】:

本质上在函数中,局部变量存储在堆栈帧中。在堆栈帧内,变量的访问顺序可以是随机的。我会推荐阅读这个:http://www.cs.uwm.edu/classes/cs315/Bacon/Lecture/HTML/ch10s07.html

考虑下面的代码

int main (void)
{
  int a = 1, b = 2, c = 3;

  c = c + 55;
  a = a + 10;

  return 0;
}

编译器可以生成以下代码

main:
.LFB0:
        .cfi_startproc
        push    rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        mov     rbp, rsp
        .cfi_def_cfa_register 6
        mov     DWORD PTR [rbp-4], 1
        mov     DWORD PTR [rbp-8], 2
        mov     DWORD PTR [rbp-12], 3
        add     DWORD PTR [rbp-12], 55
        add     DWORD PTR [rbp-4], 10
        mov     eax, 0
        pop     rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc

注意变量abc存储在位置rbp-4rbp-8rbp-12,因此每个变量都有4个字节(在我的系统中)。是负号是因为栈向下增长,而这个函数的栈帧的开始是由rbp的内容来表示的。

接下来,请注意首先c = c + 55,然后a = a + 10 不会进行推送或弹出操作,而是直接访问位置,分别使用add DWORD PTR [rbp-12], 55add DWORD PTR [rbp-4], 10。编译器将知道这些变量在堆栈帧中的位置。

在声明和访问变量之前注意push rbp。此操作将rbp(基指针,64 位)的当前值存储在堆栈帧中。接下来rbp 被更新以获取一个新值,该值指示此函数的限制。现在在这个限制内,所有的局部变量都可以被存储。还要注意返回前的pop rbp。这会从之前存储的堆栈帧中恢复rbp 的旧值,以便在ret 之后,它可以恢复到旧状态。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-03-09
    • 1970-01-01
    • 2013-07-05
    • 2014-11-19
    • 1970-01-01
    • 2019-09-08
    • 2022-12-20
    • 2013-04-02
    相关资源
    最近更新 更多