C中自动局部变量是存放在栈中的吗?

问题描述 投票:0回答:6

好吧,我知道

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 memory gcc local-variables
6个回答
8
投票

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

struct


3
投票

具有自动存储期限的对象通常存储在堆栈中,但语言标准并不要求这样做。事实上,标准(链接是最新的预发布 C11 草案) 甚至没有提到“堆栈”这个词。

不幸的是,“堆栈”这个词是含糊不清的。

从最抽象的意义上讲,堆栈是一种数据结构,其中最近添加的项将首先被删除(后进先出,或 LIFO)。关于具有自动存储持续时间的对象的生命周期的要求(即,在没有

static
关键字的函数中定义的对象)意味着 some 类堆栈分配。

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

这是一种不寻常的实现,并且有充分的理由表明这种方法不常用(连续堆栈更简单、更高效,并且通常由 CPU 支持)。但是 C 标准经过精心编写,以避免需要特定的方案,并且经过精心编写的可移植 C 代码将正确工作,无论编译器选择哪种方法。 你不需要知道。关于

var1
的地址,您真正需要知道的是它是
&var1
。如果你写
if (&var1 < &var2) { ... }
,那么你可能做错了什么(顺便说一句,该表达式的行为未定义)。

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


1
投票

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


0
投票

我可能是错的,但堆栈从较低的内存地址开始,然后添加到其中。所以 var4 位于顶部是正确的。毕竟它是一个堆栈!

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


0
投票

我 99.9999% 确信答案是 是的。 另外,堆栈在 Intel 架构机器上向下增长,而不是向上增长。下部区域成为堆栈的虚拟“顶部”(可以说,它是颠倒的)。

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

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


0
投票
#include <stdio.h>
void func() {
    double a = 1;
    double b = 2;
    int c = 4;
    double d = 8;

    printf("Address of a: %p\n", (void*)&a);
    printf("Address of b: %p\n", (void*)&b);
    printf("Address of c: %p\n", (void*)&c);
    printf("Address of d: %p\n", (void*)&d);
}
int main() {
    func();
}

“一个函数中的变量可能会被编译器移动,甚至被优化”
确实如此,我用 int 和 double 进行测试,结果似乎更难以预测,如下所示:

Address of a: 0x7fff7ea8b560
Address of b: 0x7fff7ea8b568
Address of c: 0x7fff7ea8b55c
Address of d: 0x7fff7ea8b570

地址先上下再上!

© www.soinside.com 2019 - 2024. All rights reserved.