为什么允许将指针强制转换为引用?

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平台上,你的代码会破坏指针的最重要的字节,因此将它疯狂地指向一个完全不同的位置,从而使你的程序更容易崩溃.

  • 我不知道`reinterpret_cast <T&>(x)<==>*reinterpret_cast <T*>(&x)`等价.有趣. (4认同)
  • @jalf:在5.2.10/10中这样说.任何左值都可以转换为任何其他引用类型. (2认同)

jal*_*alf 6

我花了一段时间才理解它,但我想我终于明白了。

C++ 标准指定强制转换reinterpret_cast<U&>(t)相当于*reinterpret_cast<U*>(&t).

在我们的例子中,Uchar,并且tchar*

扩展这些,我们看到发生以下情况:

  • 我们将参数的地址进行强制转换,产生类型为 的值char**
  • 我们reinterpret_cast这个值char*
  • 我们取消引用结果,产生char左值。

reinterpret_cast允许您从任何指针类型转换为任何其他指针类型。因此,从char**到 的演员阵容char*都很完善。

  • 相当于 `*reinterpret_cast&lt;U*&gt;(&amp;t)` ,具有 `&amp;` 和 `*` 运算符的内置/非重载含义,如 5.2.10/10 中所强调的。`boost::addressof` 利用了这种细微的区别。 (3认同)