在许多人都知道的C中,堆栈是所有局部变量所在的位置。堆栈是最后输出数据结构的第一个意味着您只能访问最近推送到其上的内容。所以给出以下代码:
int k = 5;
int j = 3;
short int i;
if (k > j) i = 1;
显然这是无用的代码,它没有任何实际意义,但我试图把头脑包裹起来。
对于short int i声明,我假设在堆栈上分配了2个字节。对于4个字节的int k和int j,使用值5和3分配。因此堆栈看起来如下
---------- <- stack pointer
int i
----------
int k = 5
----------
int j = 3
----------
所以对于if语句,你必须弹出int i才能达到k和j的条件,如果是的话,我会去哪里?如果这是C做局部变量的方式,这一切似乎都非常耗时且乏味。
这实际上是C是怎么做的,还是我把它全部搞砸了?
答案 0 :(得分:7)
堆栈不是堆栈。它仍然是随机访问内存,这意味着您可以在固定时间内访问任何位置。堆栈规则的唯一目的是为每个函数调用它自己的私有内存区域,该函数可以确定不被其他任何人使用。
答案 1 :(得分:4)
调用堆栈是堆栈,但它并没有像您想象的那样使用。每次从函数调用时,返回地址(程序计数器)与局部变量一起被压入堆栈。当每个函数返回时,堆栈会被称为一个&#34;堆栈帧&#34;,其中包含变量。 在每个函数中,内存被视为随机访问。生成了在堆栈上排序局部变量的代码的编译器确切地知道它们与堆栈帧指针的距离,因此不必推送和弹出各个局部变量。
答案 2 :(得分:4)
你一点都不知所措。
是的,本地(auto
)变量通常存储在堆栈中。但是,它们在读取时不会从堆栈中弹出;它们被堆栈指针的偏移量引用。
请使用以下代码:
x = y + z;
其中每个x
,y
和z
都在堆栈上分配。当编译器生成等效的机器代码时,它将通过给定寄存器的偏移量来引用每个变量,类似于:
mov -8(%ebp), %eax
add -12(%ebp), %eax
mov %eax, -4(%ebp)
在x86架构上,%ebp
是帧指针;堆栈被分解为 frames ,其中每个帧包含函数参数(如果有的话),返回地址(即函数调用后的指令的地址)和局部变量(如果有的话) )。在我熟悉的系统上,堆栈会向下发展,#34;向下&#34;朝向0,并且存储局部变量&#34;低于&#34;帧指针(低位地址),因此是负偏移量。上面的代码假定x
位于-4(%ebp)
,y位于-8(%ebp)
,z
位于-12(%ebp)
。
当函数返回时,所有内容都会从堆栈 1 中弹出,而不是之前。
修改强>
请注意,C语言定义强制要求 none 。该语言不需要使用运行时堆栈()(尽管编译器在没有编译器的情况下实现是一个婊子)。它只是将auto
变量的生命周期定义为从它们的声明结束到它们的封闭范围的结尾。堆栈使这很容易,但不是必需的。
<小时/> 1。那么,堆栈和帧指针将被设置为新值;数据将保持原样,但现在可以使用其他内容。
答案 3 :(得分:0)
堆栈的顶部,在Intel处理器和许多其他处理器上,由存储在cpu寄存器中的地址引用,称之为SP,复制到Base Pointer,称之为BP;许多机器指令允许由当前BP组合的地址表达式与字节偏移量相结合。所以,在你的例子中,我将偏移0,j将偏移-2,k将偏移-6。
if将简单地解析为地址-6(BP)和-4(BP)的内容的比较。实际的偏移值可能因实现而异;但是,这是一般的想法...