C语言的栈变量是反向存储的吗?

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

我想了解一下C语言是如何在栈上分配内存的,我一直以为栈上的变量可以像结构体成员变量那样描述,它们在栈内占据连续、连续的字节块。我一直以为栈上的变量可以像结构体成员变量那样描述,它们在栈中占据连续的、连续的字节块。为了帮助说明我在某处发现的这个问题,我创建了这个小程序,它再现了这个现象。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void function(int  *i) {
    int *_prev_int =  (int *) ((long unsigned int) i -  sizeof(int))  ;
    printf("%d\n", *_prev_int );    
}

void main(void) 
{
    int x = 152;
    int y = 234;
    function(&y);
}

看到我在做什么了吗?假设 sizeof(int) 是4:我在寻找传递的指针后面的4个字节,因为那会读出前面的4个字节,在那里 int y来电者 栈。

它没有打印152。奇怪的是,当我看了下4个字节。

int *_prev_int =  (int *) ((long unsigned int) i +  sizeof(int))  ;

现在,它的工作,打印无论在 x 在调用者的栈内。为什么要这样做?x 的地址低于 y? 堆栈变量是颠倒存储吗?

c memory memory-management memory-address
1个回答
11
投票

堆栈组织完全 不详 并且是 具体实施. 实际上,这在很大程度上取决于编译器(甚至是它的版本)和优化标志。

有些变量甚至不在堆栈中(例如,因为它们被保存在一些寄存器中,或者因为编译器对它们进行了优化--例如,通过内联,常量折叠等)。

另外,你可以有一些假设的C语言实现,它不使用任何堆栈(即使我不能说出这样的实现)。

要了解更多关于堆栈的信息。

  • 请阅读wikipage on 呼叫堆栈, 尾数, 线程以及 延续

  • 熟悉电脑的 建筑学 & 指令集 (例如 x86)&amp。ABI,然后...

  • 要求你的编译器显示汇编器代码和一些中间的编译器表示。如果使用 海湾合作委员会编译一些简单的代码,用 gcc -S -fverbose-asm (获取汇编器代码 foo.s 编译时 foo.c),并尝试多个优化级别(至少 -O0, -O1, -O2 ....). 也可以试试 -fdump-tree-all 选项(它转储了上百个文件,显示了编译器对你的源代码的一些内部表示)。注意,GCC还提供了 返回地址内置

  • 阅读Appel的旧文 垃圾回收可以比堆栈分配更快,并了解 垃圾回收 技术(因为他们经常需要检查并可能改变调用栈框架内的一些指针)。要了解更多关于GC的信息,请阅读 GC手册.

遗憾的是,我不知道任何一种低级语言(如C、D、Rust、C++、Go......)可以在语言层访问调用栈。这就是为什么为C语言编写垃圾收集器是很困难的(因为GC-s需要扫描调用栈指针)...... 但请看 玻姆的保守派 为一个非常实用的解决方案。


3
投票

现在几乎所有的处理器架构都支持堆栈操作指令(如ARM中的LDM、STM指令)。编译器借助这些实现堆栈。在大多数情况下,当数据被推入堆栈时,堆栈指针会递减(向下生长),而当数据从堆栈弹出时,堆栈指针会递增。

所以这取决于处理器架构和编译器如何实现堆栈。

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