【发布时间】:2016-06-23 09:55:30
【问题描述】:
我写了一个小程序来学习C中的堆栈指针。通常堆栈指针指向RAM的最后一个地址。例如,我在 Linux 中运行此代码,堆栈指针位于最后一个地址 (0x7fffffffffff),但变量存储在这些地址中(对于此程序):
c --> 0x7ffc67ca5c94
b --> 0x7ffc67ca5c98
a --> 0x7ffc67ca5c9c
代码:
void fun(int *ptr)
{
printf("c --> %p\n",ptr);
ptr++;
printf("b --> %p\n",ptr);
ptr++;
printf("a --> %p\n",ptr);
}
int main()
{
int a = 10,b = 20,c = 30;
printf("%p %p %p\n",&a,&b,&c);
fun(&c);
return 0;
}
此程序的输出:
0x7ffc67ca5c9c 0x7ffc67ca5c98 0x7ffc67ca5c94
c --> 0x7ffc67ca5c94
b --> 0x7ffc67ca5c98
a --> 0x7ffc67ca5c9c
我的问题是:
为什么变量没有存储在堆栈帧的最后一部分 (0x7fffffffffff) 中,它跳过了一些内存位置并被存储?这种行为有什么正当理由吗?
为什么栈指针地址有六个字节?
我正在使用带有 32 位 GCC 编译器的 64 位机器。
【问题讨论】:
-
你从哪里得到“堆栈指针地址有六个字节”?我看到应该是 4 个字节的增量(32 位地址,4 字节对齐)。
-
只要 MMU 正确处理,堆栈指针可以指向 o/s 喜欢的任何位置。您显示的值类似于我在带有 64 位编译器的 Mac OS X 上看到的值——它设计了不同的系统。您看到的不是使用 32 位编译器的结果。有大量的空闲内存空间;由系统决定如何使用它。堆栈指针有 8 个字节,与其他所有指针相同。最重要的一对字节只是零,因此
printf()不添加四个前导零。 -
旁注:您所要求的都不是由 C 语言标准规定的(而是取决于编译器实现)。
-
堆栈的其余部分可能是台式计算机需要用于可执行文件的启动代码的杂项?不过似乎太过分了,肯定连 Linux 都不会那么糟糕?
-
@JonathanLeffler 即使 CPU 可以支持 64 个地址范围,32 位程序的虚拟地址也是 32 位的。没有前导零,地址实际上是 32 位宽。
标签: c pointers memory-management stack