0

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

这里也提到了这一点

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 位的堆栈上的内存空间,那么通过*(p+1)我们应该查看地址x + 4处的内存,将另外 4 个字节“移动”到堆栈顶部。

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

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

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

4

2 回答 2

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任何处理器架构上使用我见过的任何调用约定,因为堆栈通常会向下增长。

于 2013-10-06T02:45:32.683 回答
1

Your assumptions are true in theory (From the CS point of view).

In practice there is no guarantee to do pointer arithmetic in that way expecting those results.

For example, your asumption "All function arguments are placed on the stack" is not true: The allocation of function argumments is implementation-defined (Depending on the architecture, it could use registers or the stack), and also the compiler is free to allocate local variables in registers if it feels necesary.

Also the asumption "int size is 4 bytes, so adding 4 to the pointer goes to b" is false. The compiler could have added padding between a and b to ensure memory aligment.

The conclusion here is: Don't use low-level tricks, they are implementation-defined. Even if you have to (Regardless of our advises) do it, you have to know how the compiler works and how it generates the code.

于 2013-10-05T22:36:51.690 回答