如何从堆栈中访问函数局部变量?

Posted

技术标签:

【中文标题】如何从堆栈中访问函数局部变量?【英文标题】:How are the function local variables accessed from the stack? 【发布时间】:2012-03-04 02:16:37 【问题描述】:

来自http://www.learncpp.com/cpp-tutorial/79-the-stack-and-the-heap/

以下是函数执行时发生的步骤顺序 叫:

    函数调用之外的指令地址被压入堆栈。这就是 CPU 记住后去哪里的方式 函数返回。 在堆栈上为函数的返回类型腾出空间。目前这只是一个占位符。 CPU 跳转到函数的代码。 堆栈的当前顶部保存在称为堆栈帧的特殊指针中。 在此之后添加到堆栈的所有内容都被视为函数的“本地”。 所有函数参数都放在堆栈上。 函数内部的指令开始执行。 局部变量在定义时被压入堆栈。

我不确定第 6 点的工作原理。如果所有函数参数都放在堆栈上,它们是如何访问的?

例如,如果有三个参数abc,并像这样从顶部放置在堆栈上

| a |
| b |
| c |
|   |
 ...
|___|

现在当函数想要访问c 时会发生什么? ab 弹出了吗?

【问题讨论】:

在我看来,第 3 步发生在第 6 步之前是不可能的:inside 应该有关于调用者评估的主体函数代码。废话! 【参考方案1】:

堆栈是一个隐喻堆栈。请记住它仍然是一个 RAM,因此您可以访问每个地址而无需弹出其余地址,如果您知道自己在寻找什么。

由于自动变量的大小在编译时是已知的 - 编译器为每个变量标记offset,偏移量由堆栈上的自动变量部分开始[或堆栈的头部,两者都是有效的,具体实现可能取决于架构],并且它仅通过以下方式访问它们:start + offset 用于每个变量的偏移量。

【讨论】:

在您可能遇到的每个平台上,它都是一个隐喻堆栈。如果它是一个只有 push 和 pop 操作的真正堆栈,那么如果函数需要“无序”的参数,则必须将它们弹出。 偏移量存储在内存的哪个位置? @CaisManai 偏移量在编译时是已知的,不需要存储在内存中。【参考方案2】:

不,他们不是。堆栈指针(通常是esp 注册表)指向aesp+8h 指向besp+16h 指向c 等等。无需弹出a

请注意,这是一个实现细节。你不应该担心这些。我给出的数字纯粹是理论上的,在某些架构上,降序地址被赋予后面的参数,而在另一些架构上则相反。无法保证会发生这种情况。

编辑:在我看来,这不是一个非常可靠的信息来源。它谈到堆栈和堆,但这些是实现细节,甚至可能不存在。

标准中也没有任何通过堆栈实现的限制。例如,我生成了以下代码:

void foo(int x, int y, int z)

01241380  push        ebp  
01241381  mov         ebp,esp 
01241383  sub         esp,0CCh 
01241389  push        ebx  
0124138A  push        esi  
0124138B  push        edi  
0124138C  lea         edi,[ebp-0CCh] 
01241392  mov         ecx,33h 
01241397  mov         eax,0CCCCCCCCh 
0124139C  rep stos    dword ptr es:[edi] 
    int c = x;
0124139E  mov         eax,dword ptr [x] 
012413A1  mov         dword ptr [c],eax 
    c = y;
012413A4  mov         eax,dword ptr [y] 
012413A7  mov         dword ptr [c],eax 
    c = z;
012413AA  mov         eax,dword ptr [z] 
012413AD  mov         dword ptr [c],eax 

012413B0  pop         edi  
012413B1  pop         esi  
012413B2  pop         ebx  
012413B3  mov         esp,ebp 
012413B5  pop         ebp  

所以你看,那里没有堆栈。运行时可以直接访问元素:dword ptr [x] 等。

【讨论】:

但通常堆栈的实现方式是您无法通过top()的实现以外的任何其他方式访问元素。我错过了什么? @Lazer:不。堆栈是一种数据结构,您可以在其中以恒定的时间从堆栈顶部添加和删除元素。没有人说你不能随机访问它们。【参考方案3】:

它使用堆栈指针和一个相对地址来指出c。

【讨论】:

以上是关于如何从堆栈中访问函数局部变量?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C++ 中使用堆栈 [关闭]

如何防止声明为局部变量的对象在堆栈中分配?

堆栈动态和堆栈动态数组

为啥 alloca 与创建局部变量不同?

打印所有全局变量/局部变量?

为啥在函数中用作局部变量时数组不会沿堆栈方向增长?