C 我们能得到“中间”的元素吗?堆栈";直接的?

C 我们能得到“中间”的元素吗?堆栈";直接的?,c,memory,stack,local-variables,C,Memory,Stack,Local Variables,把情况想成如下 众所周知,“堆栈段”满足于“堆栈数据结构”的存储方式;在这里,局部变量a,b,和c正是存储在这样一个内存方向上的,所以理论上我们只能访问堆栈顶部的元素 但是如果我们这样做呢 局部变量B位于A和C的中间,但我们可以得到它。

把情况想成如下

众所周知,“堆栈段”满足于“堆栈数据结构”的存储方式;在这里,局部变量a,b,和c正是存储在这样一个内存方向上的,所以理论上我们只能访问堆栈顶部的元素

但是如果我们这样做呢

局部变量B位于A和C的中间,但我们可以得到它。 <……我们可以说我们可以直接在堆栈的中间得到元素吗?


首先,C标准永远不会在任何地方发出堆栈。现在,从标准实现者开始,可以实现这样一种方式,即局部变量作为函数框架的一部分存储在堆栈内存中

现在您正在思考-堆栈总是在顶部访问,但在这里我们可以直接访问变量
b
。虽然它在某处的中间。不,你错了——问题是函数的框架,它们存储在堆栈中,并在完成时弹出(虽然实现也可以以其他方式完成,但一般来说)。这里的操作单位不是变量

通过访问
b
我们没有违反堆栈数据结构的任何规则。功能框架是以
LIFO
方式访问的框架,而不是这些框架内的变量

而且现在像那样隔离几天也有点断章取义。我们可以简单地说,它们具有自动存储持续时间。就这样。它们也可以在寄存器组中实现(标准不会阻止它们)。函数框架可能具有堆栈数据结构行为

局部变量a、b和c准确地存储在这样一个内存方向上

我不知道从哪里得到的,但这不是真的,至少在现代编译器中是这样

首先,C本身没有指定任何关于使用堆栈的内容。函数调用的实现方式由实现定义。许多常见的实现都使用类似堆栈的数据结构来实现函数调用,即最后调用的函数将首先返回

但这并不意味着局部变量存储在堆栈式结构中。编译器有很多选项,如:

  • 如果在运行时不需要,它可以完全消除变量
  • 它可以将变量放入寄存器中
  • 它可以对变量重新排序
  • 在所有这些情况下,编译器唯一能保证代码的可观察行为不会改变的东西


    由于它不在堆栈式的数据结构中存储变量,因此在中间访问变量是没有问题的。

    使用堆栈存储自动变量只是一个实现细节,标准不要求任何内容。但在较低级别上,它确实是最常见的实现。这是因为在处理器中,一个特殊的寄存器(堆栈指针)用于存储函数调用(指令调用和返回)中的返回地址。当自动变量也存储在该堆栈中时,在返回时或在块结束时回收该堆栈中的存储是很简单的。但它们不是单独推送到堆栈上的:帧指针用于存储当前块的内存区域(包括对上层帧的引用),堆栈指针在一次操作中增加,用于包含所有局部变量的帧的大小。然后通过到当前帧指针的偏移量知道这些变量。因此,它们是根据自己的地址而不是堆栈中的元素来确定的。

    我真的不知道你在问什么。编译器是否将变量的值放入堆栈取决于实现。如果不需要,编译器甚至可能不会将这些值放在堆栈中,而是放在寄存器中。作为程序员,你不必担心这些事情,编译器知道如何检索
    printf
    d
    的值。我的意思是,数据结构“stack”,即所谓的“后进先出”的存储方法,我们可以模仿这种数据结构(尽管在不同的语言中,具体的实现是不同的。例如,在C中,我们通常使用struct,但在Java中,我们使用类来模拟“堆栈”)。既然创建了“堆栈”,它就应该遵循“后进先出”的原则但是,正如你所看到的,当我们试图访问局部变量B时,我们可以很容易地得到它,即使它被存储在A和C的中间,在那个“栈”数据结构中。这怎么可能?你很困惑。C标准不使用“栈”这个词。它只要求C函数的激活为参数和局部变量提供新的存储。例如,一些实现选择使用非连续内存块的链表来实现。许多确实使用堆栈,但激活的所有变量都分配在单个块中,通常根据到寄存器(有时称为基指针或堆栈指针)。你的问题毫无意义。
    int main(void)
    {
        ...
        int a=10; //a get into the stack.
        int b=20; //b get into the stack.
        int c=30; //c get into the stack.
        ...
    }
    
    printf("b = %d",b);