原来是this question的话题,发现 OP 只是忽略了取消引用。同时,this answer让我和其他一些人思考 - 为什么允许使用 C 样式强制转换或 reinterpret_cast
将指针强制转换为引用?
int main() {
char c = 'A';
char* pc = &c;
char& c1 = (char&)pc;
char& c2 = reinterpret_cast<char&>(pc);
}
以上代码在 Visual Studio 上编译时没有任何警告或错误(关于类型转换),而 GCC 只会给你一个警告,如图所示 here .
我的第一个想法是指针以某种方式自动被取消引用(我通常使用 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";
}
显示了非常有趣的输出 here .因此,您似乎正在访问指向的变量,但与此同时,您却没有。
想法?解释?标准引号?
最佳答案
嗯,这就是 reinterpret_cast
的目的。 !顾名思义,该转换的目的是将内存区域重新解释为另一种类型的值。因此,使用 reinterpret_cast
您始终可以将一种类型的左值转换为另一种类型的引用。
这在语言规范的 5.2.10/10 中有所描述。它还说reinterpret_cast<T&>(x)
与 *reinterpret_cast<T*>(&x)
相同.
在这种情况下,您正在转换 指针 的事实完全不重要。不,指针不会自动取消引用(考虑到 *reinterpret_cast<T*>(&x)
的解释,人们甚至可能会说相反的情况:自动获取该指针的地址)。在这种情况下,指针只是“占用内存中某个区域的某个变量”。该变量的类型没有任何区别。可以是 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";
}
从实际的角度来看,在 little-endian 平台上,您的代码会覆盖指针的最低有效字节。这样的修改不会使指针指向离它原来的位置太远。因此,代码更有可能打印一些东西而不是崩溃。在 big-endian 平台上,您的代码会破坏指针的最高有效字节,从而将其疯狂地抛出以指向完全不同的位置,从而使您的程序更容易崩溃。
关于c++ - 为什么允许将指针转换为引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5924248/