Xeo*_*Xeo 26 c++ pointers casting reference
最初是这个问题的主题,它出现了OP只是忽略了dereference.同时,这个答案让我和其他一些人思考 - 为什么允许使用C风格的演员表投射指针reinterpret_cast
?
int main() {
char c = 'A';
char* pc = &c;
char& c1 = (char&)pc;
char& c2 = reinterpret_cast<char&>(pc);
}
Run Code Online (Sandbox Code Playgroud)
上面的代码在编译时没有在Visual Studio中的任何警告或错误(关于投),而GCC只会给你一个警告,如图所示这里.
我的第一个想法是指针以某种方式自动被取消引用(我正常使用MSVC,所以我没有得到GCC显示的警告),并尝试了以下内容:
#include <iostream>
int main() {
char c = 'A';
char* pc = &c;
char& c1 = (char&)pc;
std::cout << *pc << "\n";
c1 = 'B';
std::cout << *pc << "\n";
}
Run Code Online (Sandbox Code Playgroud)
这里显示了非常有趣的输出.因此,您似乎正在访问指向变量,但与此同时,您不是.
想法?解释吗?标准报价?
AnT*_*AnT 37
嗯,这就是目的reinterpret_cast
!顾名思义,该转换的目的是将内存区域重新解释为另一种类型的值.因此,使用reinterpret_cast
您始终可以将一种类型的左值转换为另一种类型的引用.
这在语言规范的5.2.10/10中描述.它也说那reinterpret_cast<T&>(x)
是一回事*reinterpret_cast<T*>(&x)
.
在这种情况下,您正在投射指针这一事实完全并不完全无关紧要.不,指针不会自动解除引用(考虑到*reinterpret_cast<T*>(&x)
解释,人们甚至可能会说相反的情况:该指针的地址是自动获取的).在这种情况下,指针只是"占据内存中某些区域的某个变量".该变量的类型无论如何都没有区别.它可以是a double
,指针,int
或任何其他左值.该变量仅被视为您重新解释为另一种类型的内存区域.
至于C风格的演员表 - 它只是被解释为reinterpret_cast
在这种情况下,所以上面的内容立即适用于它.
在第二个示例中,您附加了对c
指针变量占用的内存的引用pc
.当你这样做时c = 'B'
,你强行将值'B'
写入该内存,从而完全破坏原始指针值(通过覆盖该值的一个字节).现在,被破坏的指针指向一些不可预测的位置.后来你试图取消引用被破坏的指针.在这种情况下发生的事情是纯粹的运气.程序可能会崩溃,因为指针通常是不可分的.或者你可能会很幸运,并使你的指针指向一些不可预测但有效的位置.在这种情况下,程序将输出一些东西.没有人知道它会输出什么,并且它没有任何意义.
可以将第二个程序重写为没有引用的等效程序
int main(){
char* pc = new char('A');
char* c = (char *) &pc;
std::cout << *pc << "\n";
*c = 'B';
std::cout << *pc << "\n";
}
Run Code Online (Sandbox Code Playgroud)
从实际角度来看,在little-endian平台上,您的代码将覆盖指针的最低有效字节.这样的修改不会使指针指向太远离其原始位置.因此,代码更可能打印一些东西而不是崩溃.在big-endian平台上,你的代码会破坏指针的最重要的字节,因此将它疯狂地指向一个完全不同的位置,从而使你的程序更容易崩溃.
我花了一段时间才理解它,但我想我终于明白了。
C++ 标准指定强制转换reinterpret_cast<U&>(t)
相当于*reinterpret_cast<U*>(&t)
.
在我们的例子中,U
是char
,并且t
是char*
。
扩展这些,我们看到发生以下情况:
char**
。reinterpret_cast
这个值char*
char
左值。reinterpret_cast
允许您从任何指针类型转换为任何其他指针类型。因此,从char**
到 的演员阵容char*
都很完善。