为什么C使用堆栈来存储局部变量?这只是为了拥有独立的内存空间,还是具有在超出范围后自动清除所有局部变量和对象的功能?
我还有几个问题,
问题1)如何从指令部分引用局部变量.考虑NewThreadFunc是createThread函数调用的函数.
DWORD WINAPI NewThreadFunc(PVOID p_pParam)
{
int l_iLocalVar1 = 10;
int l_iLocalVar2 = 20;
int l_iSumLocalVar = l_iLocalVar1 + l_iLocalVar2;
}
Run Code Online (Sandbox Code Playgroud)
这个线程的堆栈看起来像这样,
| p_pParam |
| NewThreadFunc()|
| 10 |
| 20 |
| 30 |
| |
.
.
.
Run Code Online (Sandbox Code Playgroud)
现在我的问题是,在执行此函数时,CPU如何知道局部变量的地址(int l_iSumLocalVar,l_iLocalVar1和l_iLocalVar2)?这些变量不是它们存储地址的指针,它们必须从中获取值.我的问题是上面的堆栈.
问题2)如果此函数进一步调用任何其他函数,堆栈将如何表现它?据我所知,堆栈将进一步分为自身.如果这是真的,那么被调用函数的局部变量如何从被调用函数中隐藏.基本上局部变量如何维护范围规则?
我知道这些可能是非常基本的问题,但有些我怎么想不到这些问题的答案.
首先,使用堆栈作为局部变量的不是"Windows".它与"Windows"或任何其他操作系统完全无关.这是你的编译器.没有人强制您的编译器为此目的使用系统堆栈,但通常这是实现局部变量的最简单和最有效的方法.
其次,编译器使用堆栈来存储局部变量(是系统提供的堆栈或编译器实现的堆栈),因为类似堆栈的存储非常精确地匹配语言强制定义的局部变量语义.局部变量的存储持续时间由它们严格地相互嵌套的声明区域(块)定义.这立即意味着局部变量的存储持续时间遵循LIFO原则:后进先出.因此,使用堆栈(LIFO数据结构)来分配具有LIFO存储持续时间的对象是首先想到的最自然的事情.
局部变量通常通过它们从当前活动堆栈帧的开头的偏移来解决.编译器在编译时知道每个局部变量的确切偏移量.编译器通过以下方式生成将为当前函数分配堆栈帧的代码:1)在输入函数时记忆堆栈指针的当前位置(假设它存储在寄存器中R1)和2)移动当前堆栈指针存储函数的所有局部变量所需的量.一旦堆栈帧以这种方式分配的,你的局部变量l_iLocalVar1,l_iLocalVar2并且l_iSumLocalVar将简单地通过地址访问R1 + 6,R1 + 10并R1 + 14(我使用任意偏移).换句话说,特定地址值不访问局部变量,因为这些地址在编译时是未知的.而是通过计算的地址访问局部变量.它们被计算为一些运行时基址值+一些编译时偏移值.