C堆栈变量是否反向存储?

doc*_*_id 6 c stack pointers memory-address

我试图理解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);
}
Run Code Online (Sandbox Code Playgroud)

看看我在做什么?假设sizeof(int)是4:我在传递的指针后面看了4个字节,因为它会int y调用者堆栈中的位置之前读取4个字节.

它没有打印152.奇怪的是当我看下4个字节时:

int *_prev_int =  (int *) ((long unsigned int) i +  sizeof(int))  ;
Run Code Online (Sandbox Code Playgroud)

现在它可以工作,打印x调用者堆栈内的任何内容.为什么x地址低于y?堆栈变量是否颠倒存储?

Bas*_*tch 10

堆栈组织完全未指定,并且是特定于实现的.实际上,它取决于很多编译器(甚至是它的版本)和优化标志.

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

顺便说一下,你可以有一些假设的C实现,它不使用任何堆栈(即使我不能命名这样的实现).

要了解有关堆栈的更多信息:

遗憾的是,我不知道在语言级别可以访问调用堆栈的低级语言(如C,D,Rust,C++,Go,...).这就是为C编写垃圾收集器很困难的原因(因为GC-s需要扫描调用堆栈指针)......但是看看Boehm的保守GC是一个非常实用和实用的解决方案.

  • AFAIK,C99标准没有以规范的方式提及/任何堆栈. (4认同)
  • @GrijeshChauhan:实际上我认为添加这些信息弊大于利,因为太多的程序员不理解依赖于未指定/实现定义的行为的含义,并乐于使用任何"对我有用",然后想知道为什么下一个编译器或OS更新破坏了他们的代码. (2认同)