[英]reinterpret_cast behavior when dereferencing a void pointer
在与某人讨论他在这个答案的评论帖子中提出的建议时,我遇到了一些代码,gcc4.8和VS2013拒绝编译,但是clang愉快地接受它并显示正确的结果。
#include <iostream>
int main()
{
int i{ 5 };
void* v = &i;
std::cout << reinterpret_cast<int&>(*v) << std::endl;
}
现场演示 。 GCC和VC都因我预期的错误而失败,抱怨代码试图在reinterpret_cast
取消引用void*
。 所以我决定在标准中查看这个。 来自N3797, §5.2.10/ 11 [expr.reinterpret.cast]
如果可以使用
reinterpret_cast
将“指向T1
指针”类型的表达式显式转换为“指向T2
指针”类型,则可以将类型T1
glvalue表达式强制转换为“对T2
引用”。 结果引用与源glvalue相同的对象,但具有指定的类型。 [ 注:即,对于左值,基准铸造reinterpret_cast<T&>(x)
具有作为转换相同的效果*reinterpret_cast<T*>(&x)
与内置&
和*
运营商(以及类似地用于reinterpret_cast<T&&>(x)
)。 -end note ]没有创建临时,没有复制,也没有调用构造函数(12.1)或转换函数(12.3)。
在这种情况下, T1
为void
, T2
为int
,并且可以使用reinterpret_cast
将void*
转换为int*
。 因此满足所有要求。
根据说明, reinterpret_cast<int&>(*v)
与*reinterpret_cast<int*>(&(*v))
reinterpret_cast<int&>(*v)
具有相同的效果,我估计,它与*reinterpret_cast<int*>(v)
。
那么这是一个海湾合作委员会和VC的错误,还是铿锵有力,我错误地解释了这个?
事实是,演员表内的表达无效。 根据§5.3.1 一元运算符 :
一元*运算符执行间接:它所应用的表达式应该是指向对象类型的指针,或指向函数类型的指针,结果是指向表达式指向的对象或函数的左值。 如果表达式的类型是“指向T的指针”,则结果的类型为“T”。[注意:可以取消引用指向不完整类型(cv void除外)的指针。 由此获得的左值可以以有限的方式使用(例如,初始化参考); 这个左值不能转换为prvalue,见4.1。 - 结束说明]
void
不是对象类型。 所以事情停在那里,整个表达无效。 clang似乎在这里弄错了。
更重要的是, void
类型只能在特定情况下使用,如§3.9.1 基本类型 :
void类型的表达式只能用作表达式语句(6.2),作为逗号表达式(5.18)的操作数,作为?:( 5.16)的第二个或第三个操作数,作为typeid或decltype的操作数,如返回语句中的表达式(6.6.3),返回类型为void的函数,或者作为显式转换的操作数,类型为cv void。
因此,即使derefence是合法的,也不能使用void
“object”作为转换中的源(除了转换为void)。
reinterpret_cast<int&>(*v)
可能确实与*reinterpret_cast<int*>(&(*v))
具有相同的效果, 当这两个表达式都有效时 (并且当天没有花哨的运算符重载)。 仅仅因为表达式可以用有效的形式重写,并不意味着它本身是有效的。
类型的表达式void
是允许的在一个大多只是语法设备return
语句,你也可以转换为一个表达式void
,但仅此而已:没有任何类型的glvalues void
,类型的表达式void
并不是指内存。 因此,从glvalue开始的标准引用的段落不适用。 因此,铿锵是错的。
如果v
的类型为void *
,那么*v
就没有意义了。 问题不在于演员,问题在于取消引用void的指针是非法的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.