繁体   English   中英

取消引用void指针时的reinterpret_cast行为

[英]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)。

在这种情况下, T1voidT2int ,并且可以使用reinterpret_castvoid*转换为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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM