在堆栈上分配局部变量&使用指针算法

时间:2013-10-05 22:20:50

标签: c++ memory-management stack

我在函数中读到,局部变量放在堆栈上,因为它们是在参数放在那里之后定义的。

这也提到here

  

5.所有函数参数都放在堆栈上。 6.说明   函数内部开始执行。 7.推送本地变量   在定义它们时进入堆栈。

所以我怀疑如果C ++代码是这样的:

#include "stdafx.h"
#include <iostream>

int main()
{

    int a = 555;
    int b = 666;
    int *p = &a;

    std::cout << *(p+1);
    return 0;
}

如果这里的整数有4个字节,我们调用堆栈上的内存空间,其中包含int 555 x 的前8位,然后'移动'另外4个字节通过*(p+1)到堆栈的顶部我们应该查看地址 x + 4 的内存。

然而,这是-858993460的输出 - 无论int b具有什么值,它总是如此。显然它有一些标准价值。当然我正在访问一个我不应该访问的内存,因为这是变量b。这只是一个实验。

为什么我既没有得到预期的价值也没有非法的访问错误?

我的假设错在哪里?
-858993460代表什么?

2 个答案:

答案 0 :(得分:2)

其他人所说的(即“不要那样做”)绝对是真的。不要那样做。但是,要真正回答您的问题,p+1很可能指向调用者堆栈帧的指针或返回地址本身。当您在其上推送某些内容时,系统维护的堆栈指针会递减。从官方上讲,这是依赖于实现的,但我见过的每个堆栈指针(这是自16位时代以来)都是这样的。因此,如果正如您所说的那样,局部变量在初始化时被压入堆栈,&a应该== &b + 1

也许插图是有序的。假设我在没有优化的情况下编译32位x86的代码,并且在调用函数之前,堆栈指针esp为20(这对记录来说不太可能)。这就是你调用cout的行之前的内存:

4: 12 (value of p)
8: 666 (value of b)
12: 555 (value of a)
16: -858993460 (return address)

p+1,因为pint*,因此是16.此位置的内存不受保护,因为需要返回调用函数。

请注意,这个答案是学术性的;编译器的优化或处理器之间的差异可能导致意外结果。但是,我不希望任何处理器架构上的p+1 == &b与任何我见过的调用约定,因为堆栈通常会向下增长。

答案 1 :(得分:1)

您的假设在理论上是正确的(从CS的角度来看)。

在实践中,无法保证以这种方式进行指针运算,期望这些结果

例如,您的假设“所有函数参数都放在堆栈上”不成立:函数argumments的分配是实现定义的(根据体系结构,它可以使用寄存器或如果感觉有必要,编译器可以自由地在寄存器中分配局部变量。

asumption int大小也是4个字节,因此向指针添加4到b ”是假的。编译器可以在ab之间添加填充以确保内存对齐。

这里的结论是:不要使用低级技巧,它们是实现定义的。即使您必须(无论我们的建议如何),您也必须知道编译器的工作原理以及它如何生成代码。