C++ 在堆栈上定位局部变量&;使用指针算术

C++ 在堆栈上定位局部变量&;使用指针算术,c++,memory-management,stack,C++,Memory Management,Stack,我读到,在函数中,局部变量被放在堆栈上,因为它们是在参数先放在堆栈上之后定义的 也提到了这一点 5.所有函数参数都放在堆栈上。6.说明书 函数内部开始执行。7.局部变量被推送 在定义堆栈时将其添加到堆栈上 所以我认为C++代码是这样的: #include "stdafx.h" #include <iostream> int main() { int a = 555; int b = 666; int *p = &a; std::cout

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

也提到了这一点

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;
}
#包括“stdafx.h”
#包括
int main()
{
INTA=555;
int b=666;
int*p=&a;

你的假设在理论上是正确的(从CS的角度)

在实践中,不能保证以这种方式进行指针运算,期望得到这些结果

例如,您的假设“所有函数参数都放在堆栈上”是不正确的:函数参数的分配是由实现定义的(取决于体系结构,它可以使用寄存器或堆栈),并且编译器可以在必要时在寄存器中自由分配局部变量

此外,空值“
int
大小为4字节,因此向指针添加4到
b
”是错误的。编译器可以在
a
b
之间添加填充,以确保内存对齐


这里的结论是:不要使用低级技巧,它们是实现定义的。即使你必须(不管我们的建议如何)这样做,你也必须知道编译器是如何工作的以及它是如何生成代码的。你的假设在理论上是正确的(从CS的角度来看)

在实践中,不能保证以这种方式进行指针运算,期望得到这些结果

例如,您的假设“所有函数参数都放在堆栈上”是不正确的:函数参数的分配是由实现定义的(取决于体系结构,它可以使用寄存器或堆栈),并且编译器可以在必要时在寄存器中自由分配局部变量

此外,空值“
int
大小为4字节,因此向指针添加4到
b
”是错误的。编译器可以在
a
b
之间添加填充,以确保内存对齐


这里的结论是:不要使用低级技巧,它们是实现定义的。即使你必须(不管我们的建议如何)这样做,你也必须知道编译器是如何工作的以及它是如何生成代码的。其他人都说了什么(即“不要这样做”)绝对正确。不要这样做。但是,为了真正回答您的问题,
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
,因为
p
是一个
int*
,所以为16。此位置的内存不受读取保护,因为需要返回调用函数


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

还有一个人说过(即“不要那样做”)绝对正确。不要这样做。但是,为了真正回答您的问题,
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
,因为
p
是一个
int*
,所以为16。此位置的内存不受读取保护,因为需要返回调用函数


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

p+1 >是。<代码> *(p+1)< /C>是未定义的行为。不是必须做任何事情,而是改变<代码> p>代码>指向<代码> b>代码>。没有优化,<代码> *(& b+1)< /C> >在运行时,在Celru上打印1。而且,由于C++语言/标准没有任何“栈”的概念,所以句子。“所有函数参数都放在堆栈上”基本上是BS。如果你想知道的话,也有编译器优化(你可能想让你的变量
变为volatile
并搜索一个重复的…)