使用哪种类型的转换:static_cast 还是 reinterpret_cast?

11
int i = 1000;
void *p = &i;

int *x = static_cast<int*>(p);
int *y = reinterpret_cast<int*>(p);

void* 转换为 int* 应该使用哪种强制转换?为什么?


如果你还没有看过的话,建议你去看一下这篇文章:https://dev59.com/IXRC5IYBdhLWcg3wVvct。 - Paul Wheeler
6
不应该使用void *作为开始。 - Jerry Coffin
4个回答

15

static_cast提供了一种方法,可以在你的程序设计中知道指向的东西确实是一个int时进行转换。

static_cast的设计目的是用于反转任何隐式转换。由于您隐式地转换为void*,因此如果您知道您真的只是要反转以前的转换,则可以(并且应该)使用static_cast进行转换。

在这种假设下,没有任何被重新解释的东西-void是不完整的类型,意味着它没有值,因此在任何时候,您都不会将存储的int值“视为void”或将存储的“void值”视为int。void*只是一种丑陋的方式,表示“我不知道类型,但我将把指针传递给其他人来处理”。

reinterpret_cast如果您省略了细节,这些细节意味着您可能实际上正在使用与编写时不同的类型读取内存,并且请注意,您的代码的可移植性有限。

顺便说一下,在C ++中以这种方式使用void* 指针的好理由并不多。 C样式的回调接口通常可以用模板函数(对于类似标准函数qsort的任何内容)或虚拟接口(对于类似已注册侦听器的任何内容)来替换。如果您的C++代码正在使用某个C API,则当然没有太多选择。


我会在我的情况下使用 static_cast。 - user963241
你这句话的含义是,如果你不知道类型是int或正确对齐,那么应该使用reinterpret_cast<>吗? - Martin York
1
@Martin:这是一个问题还是陈述?这意味着如果您正在重新解释,应该使用reinterpret_cast,因此将是特定于实现的。在某些实现中,int的对齐要求为1,因此不会出现此问题。在另一种可能导致指针错位的实现中,相同的代码将超出其“有限的可移植性”。在另一种实现中,由于严格的别名规则,您根本无法进行类型游戏(除了char)。 - Steve Jessop

1

在当前的C++中,你不能像那段代码一样使用reinterpret_cast。对于将void*转换为int*,你只能使用static_cast(或等效的C风格转换)。

对于不同函数类型指针或不同对象类型指针之间的转换,需要使用reinterpret_cast

在C++0x中,reinterpret_cast<int*>(p)将等同于static_cast<int*>(p)。它可能会被纳入下一个WPs之一。

有一个误解,认为reinterpret_cast<T*>(p)会将p的位解释为表示T*的位。在这种情况下,它将使用p的类型读取p的值,然后将该值转换为T*。实际上,只有当您将其强制转换为引用类型时,才会发生直接使用类型T*的表示形式读取p的位的类型游戏,例如reinterpret_cast<T*&>(p)

据我所知,所有当前编译器都允许从void*进行reinterpret_cast,并且行为等同于相应的static_cast,即使在当前的C++03中不允许。如果拒绝它,将破坏大量代码,这样做没有任何动力。


在当前的C++中,你不能像那段代码一样使用reinterpret_cast。这种转换是允许的,但是你可能想要写的是该效果在标准上并没有正式保证。它不是直接保证的,而是“未指定的”。然而,对于static_castreinterpret_cast转换T* -> void* -> T保证产生原始值。由于这必须对每个指针值都成立,为了防止它,一个反常的编译器必须记录一些系统性的无谓更改,比如从void进行reinterpret_cast时添加1,反之亦然。没有人会相信这种说法。 - Cheers and hth. - Alf
@Alf 5.2.10/7 不允许将指针从或到任何类型转换为 void。void 不是一个对象类型。为什么 5.2.10/1 与 9.2/17 相矛盾? - Johannes Schaub - litb
@Johannes:嘿,你可能在形式上是正确的,因为void*不是一个“对象指针”。所有编译器都允许它。我去查查DR的... - Cheers and hth. - Alf
@Johannes:你提供了DR的链接! :-) 难怪我没有想起这个问题:这从来不是意图,有一个允许void的解决方案,并且所有编译器都允许void并且一直都这样做。所以,这只是学术上的问题。非常感谢你的提醒和链接,但我不能去掉反对票。你需要澄清这是非常非常正式的学术问题。干杯, - Cheers and hth. - Alf
@Alf Comeau在正确实现C++03方面存在许多问题。我早已放弃了它。遗憾的是,他们都是被金钱所引导,而不是真理之言。 - Johannes Schaub - litb
显示剩余10条评论


-1
从你的问题语义来看,我会选择reinterpret,因为那才是你实际上要做的事情。

我不同意,因为在这个简单的例子中,很明显知道 void* p 实际上指向一个整数,只需要进行 static_cast。reinterpret_cast 更加危险,因为如果有人搞乱了分配 void* p 的代码,它将允许一些非常奇怪的行为。 - Paul Wheeler
@Paul:如果有人搞乱了对p的赋值,例如从指向比int小的东西的指针进行赋值,那么static_cast肯定也会允许同样奇怪的行为。我认为使用static_cast的原因是为了传达转换的意图(即它不应该重新解释),但是转换本身并不能防止重新解释的发生,因为void*可以转换为任何对象指针类型,并且可以从任何对象指针类型转换。 - Steve Jessop
@Steve,我明白了,感谢你的澄清。由于我只是偶尔写C++,所以对这些东西的理解有些模糊,但基本的评论仍然适用,即static_cast更为合适。 - Paul Wheeler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接