gcc 在C语言中,自动生成的局部变量是否存储在堆栈中?

llmtgqce  于 2022-12-27  发布在  其他
关注(0)|答案(5)|浏览(162)

好的,我知道main()的自动局部变量存储在堆栈中,任何函数的自动局部变量也是如此,但是当我在gcc版本4. 6. 3上尝试以下代码时:

#include <stdio.h>

    int main(int argc, char *argv[]) {

        int var1;
        int var2;
        int var3;
        int var4;
        printf("%p\n%p\n%p\n%p\n",&var1,&var2,&var3,&var4);
        }

结果如下:

0xbfca41e0
0xbfca41e4
0xbfca41e8
0xbfca41ec

根据结果,var4在堆栈顶部,var1在堆栈底部,并且堆栈指针现在指向var1地址下面的地址......但是为什么var4在堆栈顶部而var1在堆栈底部......它在var1之后声明,所以我认为从逻辑上讲,var1应该在堆栈的顶部,而在var1之后声明的任何变量都应该在内存中位于它的下面...所以在我的示例中,如下所示:

>>var1  at 0xbfca41ec
>>var2  at 0xbfca41e8
>>var3  at 0xbfca41e4
>>var4  at 0xbfca41e0
>>and stack pointer pointing here  
..
..

编辑1:
在阅读了@AusCBloke的评论后,我尝试了以下代码:

#include <stdio.h>

 void fun(){
 int var1;
 int var2;
 printf("inside the function\n");
 printf("%p\n%p\n",&var1,&var2);

 }

 int main(int argc, char *argv[]) {

int var1;
int var2;
int var3;
int var4;


printf("inside the main\n");
printf("%p\n%p\n%p\n%p\n",&var1,&var2,&var3,&var4);
fun();
return 0;
}

结果是:

inside the main
0xbfe82d60
0xbfe82d64
0xbfe82d68
0xbfe82d6c
inside the function
0xbfe82d28
0xbfe82d2c

因此,fun()堆栈帧内的变量位于main()堆栈帧内的变量下方,根据堆栈的性质,这是正确的,..但在同一堆栈帧内,不必从上到下排序。
谢谢@AusCBloke ......你的评论帮了我很大的忙

ugmeyewa

ugmeyewa1#

这些变量不需要按照声明的顺序分配,编译器可以移动它们,甚至完全优化它们。如果你需要相对地址保持不变,使用struct

e0bqpujr

e0bqpujr2#

具有自动存储持续时间的对象通常存储在堆栈上,但语言标准并不要求这样做,事实上,the standard(链接到最新的预发布C11草案)甚至没有提到“堆栈”这个词。
不幸的是,“堆栈”这个词是模棱两可的。
在最抽象的意义上,栈是一种数据结构,其中最新添加的项被首先移除(后进先出,或LIFO)。关于具有自动存储持续时间的对象(即,在没有static关键字的函数中定义的对象)的生存期的要求暗示了某种栈式分配。
“堆栈”一词也常用来指内存中的连续区域,通常由指向最顶端元素的“堆栈指针”控制。堆栈通过将堆栈指针从基元素移开而增长,通过将堆栈指针移向基元素而收缩。(它可以向任何方向生长,朝向更高或更低的内存地址)。大多数C编译器使用这种连续堆栈来实现自动对象--但不是所有的编译器都这样做。IBM大型机系统的C编译器为来自堆状结构的函数调用分配存储空间,并且嵌套调用的地址不需要统一地按升序或降序排列。
这是一种不寻常的实现,而且有充分的理由说明这种方法不常用(连续栈更简单、更有效,并且通常被CPU支持)。但是C标准被仔细地编写以避免需要特定的方案,不管编译器选择哪种方法,精心编写的可移植C代码都能正常工作。您不需要知道。关于var1的地址,你只需要知道它是&var1,如果你写if (&var1 < &var2) { ... },那么你可能做错了什么(顺便说一句,这个表达式的行为是未定义的)。
这是标准的C语言的答案。我看到你的问题被标记为gcc。据我所知,所有版本的gcc都使用连续堆栈。但即使如此,利用这一点也几乎没有任何好处。

0lvr5msh

0lvr5msh3#

在许多(大多数)现代平台上,堆栈从内存中的较高地址增长到较低地址。也就是说,当你启动程序时,堆栈指针立即被放置到内存中的某个地址,这是由程序中的最大堆栈大小决定的。一旦东西被推入堆栈,堆栈指针实际上就向下移动。

agyaoht7

agyaoht74#

我可能是错的,但是堆栈从较低的内存地址开始,然后被添加到。所以var 4在顶部是正确的。它毕竟是一个堆栈!
编辑:汇编代码的栈指针位于内存栈的底部,无论何时添加数据,栈指针都会递增,以便下一个变量福尔斯栈的顶部。

np8igboo

np8igboo5#

我99.9999%肯定答案是**是的。此外,英特尔架构计算机上的堆栈向下增长,而不是向上增长。较低的区域成为堆栈的虚拟“顶部”(可以说是上下颠倒的)。
所以从技术上讲,变量
在堆栈内存中的顺序是正确的。

**EDIT:**不过,这可能仍然是编译器特定的。

相关问题