我曾经认为cout语句指向相同的值,即使一个以十六进制打印,其他以整数格式打印。 但今天我在g ++上运行同样的命令,发现第二个语句崩溃了。
int i1=12;
int *p1=&i1;
cout<<*(*((int***)&p1)); cout<<"\n\n "; //is same
cout<<*(int*)*(int*)&p1; cout<<"\n "; //is same
为什么有效地将第二个语句与i1
的打印值相同时会崩溃。
答案 0 :(得分:6)
你不能假装指针和整数是这样的。您的代码对类型宽度和对齐做了大量假设,使用错误的类型别名化,然后解除引用。 它的所有都有未定义的行为。如果它&#34;工作&#34;在你成为幸运之前&#34;。
将它丢弃并根据C ++语言的语义编写一些有意义的东西。
答案 1 :(得分:1)
你的假设完全错了,普通的编译器警告你:
main.cpp: In function 'int main()':
main.cpp:10:32: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
std::cout<< *(int*)*(int*)&p1 <<std::endl;
并且不需要进行c式演员表演,绝对不需要错误演员:-) ^
正确的代码是:
std::cout<< *(int*)*(int**)&p1 <<std::endl;
因为指向int的指针的地址是int**
根据要求提供更多解释: - )
评估的每一步都做了什么:
p1
是一个int *并指向你的i1
&p1
是一个int **,因为它是指向int的指针。的指针
*(&p1)
取消引用指针,使其成为指向int(int *)
*(*(&p1))
取消引用生成的指针,使其成为一个int。
你对演员表演的所作所为:
的指针的地址
&p1
再次是指向指针(int **)
(int*)&p1
!Ubs!现在编译器必须将指针指向为 指向int的指针。这是一个有效的表达,但不是很有用。
*(int*)&p1
现在编译器将(int *)解引用为int。这是 仍然是一个有效的表达式,但存储的值不能保证与以前相同。如后面所述,您将完全放弃部分值!
(int*)*(int*)&p1
现在告诉编译器它应该使用你的int值 作为指针。仍然没有崩溃但不再有效。见下一步:
*(int*)*(int*)&p1
崩溃!现在,您尝试取消引用int值。 只要int可以存储一个,这是有效的(但不是正确的代码) 有效指针。但是在64位机器上,指针主要是 64位(不是必须!)和int使用 32位(通常也不是必须的!)。结果只有一半了 使用指针并指向不是有效地址,这导致了 崩溃。
使用以下代码示例在64位计算机上获取不同的指针值:
int i1=12;
int *p1=&i1;
std::cout << (int*)*(int*)&p1 << std::endl;
std::cout << (int*)*(int**)&p1 << std::endl;
在我的32位机器上,两个值都相同。在您的机器上,如果是64位,您将看到不同的值!并且第一个值不再指向有效地址。而且在我的32位机器上,编译器警告错误使用指针。你永远不应该忽略编译器警告!
在我的32位机器上,你编写的代码工作正常,但是未定义的行为也会导致编译器警告。
希望有所帮助: - )