【问题标题】:does the automatic local variable are stored in the stack in C?自动局部变量是否存储在C中的堆栈中?
【发布时间】:2012-07-16 22:09:15
【问题描述】:

好的,我知道 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 .....您的评论对我帮助很大

【问题讨论】:

  • 调用堆栈可以向上或向下,具体取决于架构。
  • 请注意,C语言并没有说明你的本地变量在源代码中的顺序是否与编译程序中的顺序相同。 (它们甚至被一起优化掉了)。
  • @user315052 .... 我正在使用 x86
  • @Opetmar:这不是了解堆栈增长情况的好方法。尝试检查main 调用的函数中变量的地址以及该函数调用的变量,即。不同堆栈帧中的变量。您正在比较同一堆栈帧中变量的地址,因此它取决于编译器要在该帧中对它们进行排序的位置。查看 main 的反汇编,您可能会在堆栈指针上看到一个减法操作,它将所有这些变量分配在一个块中。
  • 另外请注意,这种调查通常很少告诉您 c 的工作原理,因为您可以通过这种方式查看的几乎所有细节都留给了实现。所以你所学到的只是那个特定的编译器是如何工作的。

标签: c memory gcc local-variables


【解决方案1】:

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

【讨论】:

  • 由于程序获取这些变量的地址,因此它们必须都分配有地址,并且地址对于同一函数的每个(可能是递归或多线程的)单独调用必须是唯一的。在实践中,实现这一要求的唯一方法是在堆栈上分配空间。
【解决方案2】:

具有自动存储持续时间的对象通常存储在堆栈中,但语言标准不需要它。其实the standard(链接是最新的C11预发布草案) 甚至没有提到“堆栈”这个词。

不幸的是,“堆栈”这个词是模棱两可的。

在最抽象的意义上,堆栈是一种数据结构,其中最近添加的项首先被删除(后进先出,或 LIFO)。具有自动存储持续时间的对象(即在没有static 关键字的函数中定义的对象)的生命周期要求意味着某种类似于堆栈的分配。

“堆栈”一词也通常用于指代内存的连续区域,通常由指向最顶部元素的“堆栈指针”控制。堆栈通过将堆栈指针移离基址而增长,并通过将其移向基址而收缩。 (它可以向任一方向增长,朝向更高或更低的内存地址。)大多数 C 编译器使用这种连续堆栈来实现自动对象——但并非所有编译器都这样做。 IBM 大型机系统已经有 C 编译器,它们从类似堆的结构中为函数调用分配存储空间,并且嵌套调用的地址不需要统一按升序或降序排列。

这是一个不寻常的实现,并且有很好的理由表明这种方法不常用(连续堆栈更简单、更高效,并且通常由 CPU 支持)。但是 C 标准是精心编写的,以避免需要特定的方案,并且精心编写的可移植 C 代码无论编译器选择哪种方法都可以正常工作。 您无需知道。关于var1 的地址,你真正需要知道的是它是&amp;var1。如果你写if (&amp;var1 &lt; &amp;var2) { ... },那么你可能做错了什么(那个表达式的行为是未定义的,顺便说一句)。

这是标准的 C 答案。我看到你的问题被标记为。据我所知,所有版本的 gcc 都使用连续堆栈。但即便如此,利用这一点也很少有任何好处。

【讨论】:

    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

      我可能是错的,但堆栈从较低的内存地址开始,然后被添加到。所以 var4 在上面是正确的。毕竟是栈!

      edit:它后面的汇编代码在内存堆栈的底部有堆栈指针,每当添加数据时,堆栈指针就会递增,以便下一个变量落在顶部。

      【讨论】:

      • 好吧,我想也许你可以解释一下上面的行为?
      • 不,..堆栈从较高的内存地址开始,堆栈指针始终指向堆栈的顶部..每次将新元素压入堆栈时,堆栈指针都会下降一步,并且指向较低的地址
      【解决方案5】:

      我 99.9999% 确定答案是 是的。 此外,堆栈在英特尔架构机器上向下增长,而不是向上增长。较低的区域成为堆栈的虚拟“顶部”(可以说是颠倒的)。

      所以从技术上讲,变量在堆栈内存中的顺序正确。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-05
        • 2015-04-18
        • 2019-09-08
        • 2021-12-18
        • 2016-01-19
        相关资源
        最近更新 更多