Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/tfs/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么允许将指针强制转换为引用?_C++_Pointers_Casting_Reference - Fatal编程技术网

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

C++ 为什么允许将指针强制转换为引用?,c++,pointers,casting,reference,C++,Pointers,Casting,Reference,最初是讨论的主题,后来发现OP忽略了去参考。与此同时,让我和其他一些人思考——为什么允许使用C风格的cast或reinterpret\u cast来投射指向引用的指针 int main() { char c = 'A'; char* pc = &c; char& c1 = (char&)pc; char& c2 = reinterpret_cast<char&>(pc); } intmain(){ 字符c

最初是讨论的主题,后来发现OP忽略了去参考。与此同时,让我和其他一些人思考——为什么允许使用C风格的cast或
reinterpret\u cast
来投射指向引用的指针

int main() {
    char  c  = 'A';
    char* pc = &c;

    char& c1 = (char&)pc;
    char& c2 = reinterpret_cast<char&>(pc);
}
intmain(){
字符c='A';
char*pc=&c;
字符和c1=(字符和)pc;
char&c2=重新解释铸件(pc);
}
上面的代码在VisualStudio上编译时没有任何警告或错误(关于强制转换),而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";
}
#包括
int main(){
字符c='A';
char*pc=&c;
字符和c1=(字符和)pc;

std::cout当你使用C风格的cast或reinterpret_cast进行转换时,你基本上是在告诉编译器换个角度看(“你不介意,我知道我在做什么”)


C++允许您告诉编译器这样做。这并不意味着这是一个好主意…

好吧,这就是重新解释强制转换的目的。
!顾名思义,该强制转换的目的是将内存区域重新解释为另一种类型的值。因此,使用
重新解释强制转换
您始终可以强制转换的左值一种类型指向另一种类型的引用

语言规范的5.2.10/10中描述了这一点。它还说,
reinterpret\u cast(x)
*reinterpret\u cast(&x)
是一样的

在这种情况下,您正在强制转换指针这一事实完全不重要。不,指针不会自动取消引用(考虑到
*reinterpret\u cast(&x)
解释,甚至可以说相反的情况是正确的:该指针的地址是自动获取的)。在本例中,指针仅用作“占用内存中某个区域的某个变量”。该变量的类型没有任何区别。它可以是
double
、指针、
int
或任何其他左值。该变量仅被视为内存区域,您可以将其重新解释为另一类型

至于C风格的cast——在这种情况下,它被解释为
reinterpret\u 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";
}
intmain(){
字符*pc=新字符('A');
字符*c=(字符*)&pc;

我花了一段时间摸索,但我想我终于找到了

C++标准指定了一个Case<代码> RealTytCase:t(/Cuth>),等同于代码> *RealTytCase[/>,>< /P> 在我们的例子中,

U
char
,而
t
char*

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

  • 我们将参数的地址转换为cast,生成类型为
    char**
    的值
  • 我们
    将该值重新解释为
    char*
  • 我们取消对结果的引用,生成一个
    char
    左值

<代码> RealTytRask允许您从任何指针类型转换为任何其他指针类型。因此,从<代码> char **/COD>到 char */COD>的格式是良好的。

允许,因为在您抛出时,C++允许任何东西。

但就行为而言:

  • pc是一个4字节的指针
  • (char)pc试图将指针解释为字节,特别是四个字节中的最后一个
  • (char&)pc是相同的,但返回对该字节的引用
  • 当你第一次打印电脑时,什么都没有发生,你看到了你储存的信件
  • c='B'修改了4字节指针的最后一个字节,所以它现在指向其他的东西
  • 当您再次打印时,您现在指向一个解释结果的不同位置

由于指针的最后一个字节被修改,新的内存地址就在附近,使得它不太可能在你的程序不允许访问的一块内存中。这就是为什么你不会得到SEG错误的原因。得到的实际值是未定义的,但很可能是零,这解释了当它被解释为char时的空白输出。

p> 我将尝试用我对引用和指针根深蒂固的直觉来解释这一点,而不是依赖于标准的语言

  • C没有引用类型,它只有值和指针,
    因为,在内存中,我们只有值和指针
  • 在C++中,我们添加了语法的引用,但可以将它们看作是一种语法糖——没有特殊的数据结构或内存布局方案来保存引用。
那么,从这个角度来看,什么是引用?或者更确切地说,你将如何“实现”引用?当然是用指针。因此,每当你在某些代码中看到引用时,你可以假装它实际上只是一个以特殊方式使用的指针:if
intx;
int&y{x}
那么我们真的有一个
int*y\u ptr=&x