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

时间:2015-02-17 09:48:41

标签: c pointers stack 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);
}

看看我在做什么?假设sizeof(int)为4:我在传递的指针后面看了4个字节,因为它会读取调用者int y之前的4个字节叠加。

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

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

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

3 个答案:

答案 0 :(得分:10)

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

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

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

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

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

答案 1 :(得分:3)

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

因此,它取决于处理器架构和编译器如何实现堆栈。

答案 2 :(得分:1)

取决于编译器和平台。只要由程序一致地完成同一件事(在这种情况下,是编译器翻译为程序集,即机器代码),并且平台支持该程序(好的编译器会尝试优化程序集以获得“最大的效果”),则可以用多种方法完成同一件事。 ”)。

一个很好的资料,可以深入了解c的幕后知识,编译程序时会发生什么以及为什么会发生,这是一本免费的书,逆向工程入门(理解汇编语言)。丹尼斯·尤里切夫(Dennis Yurichev),the latest version can be found at his site