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

前端之家收集整理的这篇文章主要介绍了C堆栈变量是否反向存储?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我试图理解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个字节,因为它会读取调用者堆栈中int y之前的4个字节.

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

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

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

解决方法

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

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

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

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

>阅读call stacks,tail calls,threadscontinuations上的wikipage
>熟悉您的计算机architecture& instruction set(例如x86)& ABI,然后……
>让您的编译器显示汇编代码和/或一些中间编译器表示.如果使用GCC,使用gcc -S -fverbose-asm编译一些简单的代码(在编译foo.c时获取汇编代码foo.s)并尝试几个优化级别(至少-O0,-O1,-O2 …. ).还可以尝试-fdump-tree-all选项(它会转储数百个文件,显示代码的编译器的内部表示).请注意,GCC还提供return address builtins
>在garbage collection can be faster than stack allocation阅读Appel的旧论文,并了解garbage collection技术(因为他们经常需要检查并可能更改调用堆栈帧内的一些指针).要了解有关GC的更多信息,请阅读GC handbook.

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

猜你在找的C&C++相关文章