当我在使用C ++中的指针搞乱时,我遇到了一个奇怪的输出。不太确定这是否会在其他编译器上提供相同的输出,但我已经尝试了GCC 5.1.0,4.8.1并且结果是相同的。
int main(){
int a = 10;
int b = 40;
int *ptrA = &a;
cout<<*(ptrA-1);
int *ptrB = &b;
return 0;
}
我在这段代码中正在尝试访问堆栈帧中声明的下一个变量。由于堆栈从虚拟内存的顶部增长到底部,我从ptrA
中减去1,以便将其指向存储b
的下一个4位。在这种情况下,输出为40.
删除行
时会出现“异常” int *ptrB = &b;
在这种情况下,相同的代码输出65(其他编译器给我的输出与GCC不同,但在删除此行之后,输出再次与初始代码的输出不同)。 现在出现两个问题。
cout<<*(ptrA-1);
之后的简单指针初始化语句如何以这种方式影响程序?int *ptrB = &b;
,程序不打印b?答案 0 :(得分:3)
您正在调用未定义的行为。在这种情况下如何体现这一点可以通过查看从您的代码示例生成的汇编代码来确定(为此,使用g++
选项调用-S
。)但有一种可能性是当您不要取b
的地址,优化器会优化该变量。
答案 1 :(得分:2)
你不应该对堆栈布局做出任何反应。你做的是未定义的行为,充满惊喜。
添加附加本地指针变量的定义会影响堆栈的布局。编译器可以在声明时执行此操作,或者在准备函数的堆栈帧时已经预留了一些空间。这解释了附加行如何影响结果。当然,这完全取决于实现。
标准仅在同一对象/数组中定义指针算术:
5.7 / 4:出于这些运营商的目的[即。加/减法],指向非阵列对象的指针表现为与指向第一个元素的指针相同 一个长度为1的数组,其中对象的类型为其元素 类型。
5.7 / 5:(...)如果表达式P指向数组对象的第i个元素,则表达式(P)+ N 和(P)-N(其中N具有值n)分别指向阵列的第i + n和第i-n个元素 对象,如果它们存在。 (...)如果指针操作数和结果都指向元素 相同的数组对象,或者超过数组对象的最后一个元素, 评估不得产生溢出;否则,行为 未定义。
您可能对使用不同编译选项更改堆栈布局的this response感兴趣。