有人可以解释以下代码中发生了什么吗?
char cd[1024];
unsigned short int & messageSize =reinterpret_cast<unsigned short int&>(*cd);
是否通过引用获取cd的前2个字符并将其转换为16位int? 当我删除'&amp;'时,编译器抱怨无法从char转换为unsigned short int。
unsigned short int messageSize =reinterpret_cast<unsigned short int>(*cd);
答案 0 :(得分:3)
&#34;直观&#34; reinterpret_cast
的含义是&#34;取一个位序列并将其视为该位序列具有不同的类型&#34;。对于char
和unsigned short
类型,这是不可能的,因为它们的宽度不同。
至于第一种情况,直觉是:reinterpret_cast
将左值引用视为指向它引用的类型的指针(并将所提到的转换应用于该指针)。
正式地,标准说:
4.2数组到指针的转换[conv.array]
- 类型为“N T数组”或“未知T的数组”的左值或右值可以转换为“指向T的指针”类型的prvalue。结果是指向数组第一个元素的指针。
醇>
和
5.3.1一元运算符[expr.unary.op]
- 一元
醇>*
运算符执行间接:应用它的表达式应该是指向对象类型的指针,或指向函数类型的指针,结果是引用对象或函数的左值 表达点所指向的。如果表达式的类型是“指向T的指针”,则结果的类型为 “T”。
因此,在解除引用*cd
之后,我们会得到一个char
类型的左值(就像你写cd[0]
一样)。
5.2.10重新解释演员[expr.reinterpret.cast]
- 如果使用
醇>reinterpret_cast
可以将“指向T1的指针”类型的表达式显式转换为“指向T2的指针”类型,则可以将类型T1的glvalue表达式强制转换为“对T2的引用”类型。结果引用与源glvalue相同的对象,但具有指定的类型。 [注意:也就是说,对于左值,参考广告reinterpret_cast<T&>(x)
与内置*reinterpret_cast<T*>(&x)
和&
运算符的转化*
具有相同的效果(同样适用于reinterpret_cast<T&&>(x)
)。 - 尾注]没有创建临时,没有复制,也没有调用构造函数(12.1)或转换函数(12.3)。
这意味着,你有类似
的东西*reinterpret_cast<unsigned short *>(&cd[0])
但是,或许比以上所有更重要的是:
3.10 Lvalues和rvalues [basic.lval]
如果程序试图通过访问对象的存储值 行为是除以下类型之一以外的glvalue 未定义:
- 对象的动态类型,
- 对象的动态类型的cv限定版本,
- ...
- char或unsigned char类型。
即绑定&#34;引用char&#34;对于#&#34; unsigned short&#34;没关系。但是反之亦然(例如,在你的例子中)并不好,因为访问这样的引用会调用未定义的行为。
答案 1 :(得分:1)
使用引用进行强制转换不同于没有引用的同一强制转换 - 没有引用的强制转换会创建一个新的临时对象,而使用引用进行强制转换会更改已存在对象的类型。这在很多情况下很重要,例如,在您的情况下,因为您将结果分配给非const引用。非const引用不能用临时对象进行初始化。
在旁注中,您知道您在此处所做的是违反类型别名规则,并且会产生不确定的行为吗?
答案 2 :(得分:1)
unsigned short int & messageSize
表示messageSize
是unsigned short int
类型的变量,存储该变量的内存区域应作为初始值。
初始值设定项=reinterpret_cast<unsigned short int&>(*cd)
说:在cd
指向的位置取内存,并假装它包含unsigned short int
。
结果是,如果您尝试读写messageSize
,那么您将尝试在包含其他内容的内存位置中读取和写入unsigned short int
。这会导致未定义的行为。
在某些情况下可以假装内存位置包含实际上没有的对象;这不是其中的一个。
如果您的编译器没有执行别名优化,那么可能会出现,就好像您的代码现在“正常”一样。但是代码被破坏了。
答案 3 :(得分:0)
reinterpret_cast<unsigned short int&>(*cd);
类似于
*reinterpret_cast<unsigned short int*>(cd);