让我们看下面的代码:
int i = 10;
char c = reinterpret_cast<char&>(i);
如果可以使用reinterpret_cast将“指向T1的指针”类型的表达式显式转换为“指向T2的指针”类型,则可以将类型T1的glvalue表达式强制转换为“对T2的引用”类型。结果指向与源glvalue相同的对象,但是具有指定的类型。
因此,具有指定reinterpret_cast<char&>(i)
类型的char
左值是指int
对象i
。
要初始化c
,我们需要值,因此要应用从左值到右值的转换[conv.lval]/3.4:
glvalue指示的对象中包含的值是prvalue结果。
L2R转换的结果是i
对象中包含的值。只要i
的值在char
可表示的范围内([expr]/4表示否则为UB),则变量c
应该被初始化为具有相同的值。值。
从实现POV来看,在小端平台上,可以通过读取i
对象地址处的字节来轻松实现。但是,在大端平台上,编译器将必须添加偏移量以获取最低有效字节。或者,将整个int
对象读入寄存器并屏蔽第一个字节,这在两个字节序上都是可以接受的。
如果您认为上面的代码可以很容易地被编译器处理以生成符合C ++ 17标准要求的代码,请考虑将指针指向指向int
的指针i
指向char
的指针。这样的强制转换不会更改指针值,即它仍然指向int
对象i
,这意味着通过以下L2R转换将间接操作符应用于此类指针应具有如上所述的作用,也就是说,如果int
类型可以表示的话,则获取char
对象的值。
在以下代码中
int i = 10;
f(reinterpret_cast<char*>(&i)); // void f(char*)
如果编译器不知道函数i
对其参数做些什么,编译器是否应该将f
的地址调整一些偏移量?而且,编译器也不知道将传递给函数f
的内容。上面的代码和函数f
位于不同的翻译单元中。
例如,如果f
取消引用指针以通过它读取值,则如上所述,它将获得i
的值。但是它也可以使用指向实际char
对象的指针来调用,因此f
无法调整给定的指针。这意味着调用方应调整指针。但是如果f
传递指向memcpy
的指针以将sizeof(int)
个字节复制到此大小的字符数组并按照{{3}的允许复制回另一个int
对象,该怎么办? }?很难想象如何在此处调整指针以达到所需的行为(通过[basic.types]/3和[basic.types]/3)。
那么,如果有确实符合C ++ 17标准的现有实现,那么现有的实现有什么作用?
答案 0 :(得分:8)
编辑:完全重写:您已经使我确信该标准已被破坏。
...结果指向与源glvalue相同的对象,但是具有指定的类型。
glvalue指示的对象中包含的值是prvalue结果。
我同意直译可能会得出您的结论。
鉴于您的解释,reinterpret_cast
(以及用reinterpret_cast
定义的任何内容)变得无用,不仅在BE系统上,而且在LE系统上,也无法实施(请考虑在非整型和char
)。因此,我不认为这是预期的含义。这可以被视为缺陷报告的候选者。
该混淆可能是由于对表达式“包含在”中的值,“指示的对象” 和”的准确定义不足导致的“ 。澄清或改写其中的一些或全部可能是有条理的。
答案 1 :(得分:5)
[intro.object]/1说,对于非多态对象,“在其中找到的值的解释取决于用于访问它们的表达式(Clause [expr])的类型。 “
(强调是标准本身,而不是我的)
您已经注意到,这种情况下的表达式的类型为char
,因此编译器不需要将此值解释为int
类型的某些对象的值。
答案 2 :(得分:-1)
但是,在大端平台上,编译器将必须添加偏移量以获取最低有效字节。或者,将整个int对象读入寄存器并屏蔽第一个字节,这在两个字节序上都是可以接受的。
只有当您传递i
的值时,这才是正确的。但是,对于reinterpret_cast<char&>
,您传递的是地址,因为引用只是指针的语法不同。因此,c
将获得i
的MSB值,只要0
就是sizeof(int) > 1
。
您写的与以下内容没有区别:
int i = 10;
char c = *reinterpret_cast<char*>(&i);