为什么print语句会更改指针的值? 我编写了这样的C++代码: #include <iostream> using namespace std; int main() { int i = 2; int i2 = 0; void *pi = &i - 1; cout << "by cout - the value of *pi is: " << *(int*)pi << endl; printf("by printf - the value of *pi is: %d\n", *(int*)pi); printf("the address of pi is: %p\n", pi); printf("the address of i2 is: %p\n", (void*)&i2); printf("the value of i2 is: %d\n", i2); return 0; }
为什么print语句会更改指针的值? 我编写了这样的C++代码: #include <iostream> using namespace std; int main() { int i = 2; int i2 = 0; void *pi = &i - 1; cout << "by cout - the value of *pi is: " << *(int*)pi << endl; printf("by printf - the value of *pi is: %d\n", *(int*)pi); printf("the address of pi is: %p\n", pi); printf("the address of i2 is: %p\n", (void*)&i2); printf("the value of i2 is: %d\n", i2); return 0; },c++,pointers,c++11,C++,Pointers,C++11,现在,如果我删除将打印地址的语句 #include <iostream> using namespace std; int main() { int i = 2; int i2 = 0; void *pi = &i - 1; cout << "by cout - the value of *pi is: " << *(int*)pi << endl; printf("by printf - the
现在,如果我删除将打印地址的语句
#include <iostream>
using namespace std;
int main() {
int i = 2;
int i2 = 0;
void *pi = &i - 1;
cout << "by cout - the value of *pi is: " << *(int*)pi << endl;
printf("by printf - the value of *pi is: %d\n", *(int*)pi);
// printf("the address of pi is: %p\n", pi);
// printf("the address of i2 is: %p\n", (void*)&i2);
printf("the value of i2 is: %d\n", i2);
return 0;
}
请注意,该值完全不同
更新:
如果我在打印后添加一些作业:
#include <iostream>
using namespace std;
int main() {
int i = 2;
int i2 = 0;
void *pi = &i - 1;
cout << "by cout - the value of *pi is: " << *(int*)pi << endl;
printf("by printf - the value of *pi is: %d\n", *(int*)pi);
// printf("the address of pi is: %p\n", pi);
// printf("the address of i2 is: %p\n", (void*)&i2);
pi = &i2;
printf("the value of i2 is: %d\n", i2);
return 0;
}
使用“g++-std=c++11-pedantic-Wall”进行编译,版本为4.9.2
为什么会发生这种情况?访问
pi
是未定义的行为,因为&i-1
可能不是有效的指针值
<标准>(从C++标准),在5.5.3.1/3,我们有:
[…]对于指针算法(5.7)和比较(5.9,5.10),如果对象不是数组元素,则其地址以这种方式获取,则该对象被视为属于具有一个T类型元素的数组
这就引出了§5.7/4:
将具有整数类型的表达式添加到指针或从指针中减去时,结果具有指针操作数的类型。如果指针操作数指向数组对象的某个元素,且数组足够大,则结果将指向与原始元素偏移的元素,以便生成的数组元素与原始数组元素的下标之差等于整数表达式。[…]如果指针操作数和结果都指向同一数组对象的元素,或超过数组对象最后一个元素的元素,则计算不应产生溢出;否则,行为是未定义的
是的,如前所述,您的程序具有未定义的行为。你不能像这样胡乱使用指针,期望行为一致 为什么??因为编译器是一种复杂的生物,会产生各种各样的奇怪的魔法,破坏你对内存布局的期望 在本例中,您只是假设
i2
将位于内存中i
的前面。这种假设是没有根据的。虽然在您的工作示例中恰好是这样,但当您的程序没有通过获取其地址(在“打印语句”中的&i2
)来强制i2
占用内存时,该变量显然已完全优化。它根本不存在于记忆中
因此,尝试猜测其内存位置并打印所述内存位置下的值并不符合您的预期也就不足为奇了
C++是一种抽象。它是特意设计的,它知道这类事情实际上是编译器的选择,不能提前预测。这就是为什么C++说你的代码有未定义的行为:因为它可能看起来像你想做的那样,或者它会蒙骗猫,把身体传送到你的车靴里,或者它可能会把你辛苦赚来的积蓄转入我的银行账户;如果您想按照标准编码,只需避免未定义的行为,只假设标准的保证,所有这些不确定性就会消失在一片混乱中。WTF:
void*pi=&i-1
和*(int*)pi
(换句话说:你不知道,你在做什么,请阅读一些书)请查看g++-S
@DieterLücking的输出为此道歉,发现差异是一个意外。。我永远不会在其他情况下使用它。谢谢。@timrau我正在读汇编代码,谢谢。但我觉得我现在确实有了一个“代码>未定义的< /COD>”的感觉。基本上,C++程序中的每个问题都可以用未定义的行为来解释。C++标准也采用了这个措辞。参见§5.7/4。这是未定义的,好的,我想我现在真的理解了这个意思。谢谢。@piratf:请停止写非代码的东西。代码格式。
@piratf这与其说是对你的问题的评论,不如说是对你的评论的回应。“未定义的行为”不是代码。“unvalid”不是代码。请不要将它们标记为代码。对于您的问题,对于“输出”部分,理想情况下不要将其标记为代码(而是使用
,这样您不会得到无效的语法突出显示),但将其标记为代码比随机单词更糟糕。谢谢您的解释,我不会“猜测”再也没有未定义的行为了。@piratf:太好了:)我喜欢最后一段!
by cout - the value of *pi is: 2004212408
by printf - the value of *pi is: 2004212408
the value of i2 is: 0
#include <iostream>
using namespace std;
int main() {
int i = 2;
int i2 = 0;
void *pi = &i - 1;
cout << "by cout - the value of *pi is: " << *(int*)pi << endl;
printf("by printf - the value of *pi is: %d\n", *(int*)pi);
// printf("the address of pi is: %p\n", pi);
// printf("the address of i2 is: %p\n", (void*)&i2);
pi = &i2;
printf("the value of i2 is: %d\n", i2);
return 0;
}
by cout - the value of *pi is: 0
by printf - the value of *pi is: 0
the value of i2 is: 0