好吧,我知道
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.....你的评论对我帮助很大
不要求这些变量按照声明的顺序进行分配。它们可以被编译器移动,甚至完全优化掉。如果您需要相对地址保持不变,请使用
struct
。
具有自动存储期限的对象通常存储在堆栈中,但语言标准并不要求这样做。事实上,标准(链接是最新的预发布 C11 草案) 甚至没有提到“堆栈”这个词。
不幸的是,“堆栈”这个词是含糊不清的。
从最抽象的意义上讲,堆栈是一种数据结构,其中最近添加的项将首先被删除(后进先出,或 LIFO)。关于具有自动存储持续时间的对象的生命周期的要求(即,在没有
static
关键字的函数中定义的对象)意味着 some 类堆栈分配。
“堆栈”一词也常用于指代连续的内存区域,通常由指向最顶层元素的“堆栈指针”控制。通过将堆栈指针移离基址,堆栈会增长;通过将堆栈指针移向基址,堆栈会缩小。 (它可以向任一方向增长,向更高或更低的内存地址增长。)大多数 C 编译器使用这种连续堆栈来实现自动对象,但并非全部都这样做。 IBM 大型机系统已经有 C 编译器,它们为来自类似堆的结构的函数调用分配存储空间,并且嵌套调用的地址不需要统一按升序或降序排列。
这是一种不寻常的实现,并且有充分的理由表明这种方法不常用(连续堆栈更简单、更高效,并且通常由 CPU 支持)。但是 C 标准经过精心编写,以避免需要特定的方案,并且经过精心编写的可移植 C 代码将正确工作,无论编译器选择哪种方法。 你不需要知道。关于
var1
的地址,您真正需要知道的是它是 &var1
。如果你写 if (&var1 < &var2) { ... }
,那么你可能做错了什么(顺便说一句,该表达式的行为未定义)。
这是标准答案C。我看到你的问题被标记为gcc。据我所知,所有版本的 gcc 都使用连续的堆栈。但即便如此,利用这一点也几乎没有任何好处。
在许多(大多数)现代平台上,堆栈从内存中的较高地址增长到较低地址。 IE。当您启动程序时,堆栈指针立即被放置到内存中的某个地址,该地址由程序中的最大堆栈大小决定。一旦东西被推入堆栈,堆栈指针实际上会移动向下。
我可能是错的,但堆栈从较低的内存地址开始,然后添加到其中。所以 var4 位于顶部是正确的。毕竟它是一个堆栈!
编辑:其背后的汇编代码的堆栈指针位于内存堆栈的底部,每当添加数据时,堆栈指针就会递增,以便下一个变量落在顶部。
我 99.9999% 确信答案是 是的。 另外,堆栈在 Intel 架构机器上向下增长,而不是向上增长。下部区域成为堆栈的虚拟“顶部”(可以说,它是颠倒的)。
因此从技术上讲,变量在堆栈内存中的顺序是正确的。
编辑: 不过,这可能仍然是特定于编译器的。
#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
地址先上下再上!