在将void*
指针转换为另一个指针类型时,static_cast
和reinterpret_cast
似乎都可以正常工作。是否有理由更喜欢其中一种?
在将void*
指针转换为另一个指针类型时,static_cast
和reinterpret_cast
似乎都可以正常工作。是否有理由更喜欢其中一种?
static_cast
:它是最狭窄的转换,正好描述了此处进行的转换。reinterpret_cast
会更匹配,因为它意味着“完全忽略类型安全性,只是将A强制转换为B”。reinterpret_cast
的效果。相反,reinterpret_cast
有多重含义,“由reinterpret_cast
执行的映射是实现定义的。” [5.2.10.3]void*
转换为T*
的特定情况下,映射完全由标准定义;即将类型分配给无类型指针而不改变其地址。static_cast
的原因。reinterpret_cast
都是相当危险的,因为它(对于指针)可以将任何内容转换为任何其他内容,而static_cast
更加严格,因此提供了更好的保护级别。这已经让我避免了一些错误,其中我不小心试图将一个指针类型强制转换为另一个指针类型。static_cast
更适合将void*
转换为其他类型的指针。
当两种类型之间存在一种自然、直观的转换,但不一定保证在运行时能够成功时,static_cast
是首选的类型转换方式。例如,您可以使用static_cast
将基类指针转换为派生类指针,在某些情况下这种转换是有意义的,但在运行时无法验证。类似地,您可以使用static_cast
将int
转换为char
,这是明确定义的,但在执行时可能会导致精度损失。
另一方面,reinterpret_cast
是一个设计用于执行根本不安全或不可移植的转换的强制转换操作符。例如,您可以使用reinterpret_cast
将void *
转换为int
,如果您的系统恰好具有sizeof(void*)
≤ sizeof(int)
,则可以正确工作。您还可以使用reinterpret_cast
将float *
转换为int *
或反之亦然,这是特定于平台的,因为float
和int
的特定表示不保证彼此具有任何共同之处。
简而言之,如果您发现自己正在进行一个转换,其中强制转换在逻辑上是有意义的,但运行时可能无法成功,请避免使用reinterpret_cast
。如果您有一些先验知识,认为强制转换在运行时是有效的,并且向编译器传达“我知道这可能不起作用,但至少它有意义并且我有理由相信它将正确地执行正确的事情在运行时。”编译器可以检查强制转换是否在相关类型之间,如果不是,则报告编译时错误。使用reinterpret_cast
来完成指针转换完全绕过了编译时的安全检查。
有一些情况下,您可能需要使用dynamic_cast
而不是static_cast
,但这些情况大多涉及类层次结构中的强制转换,有时直接涉及void*
。
至于规范更喜欢哪种,两者都没有过度提到“使用的正确方式”(或者至少我不记得有一个被提到过)。然而,我认为规范希望您使用static_cast
而不是reinterpret_cast
。例如,在使用C样式强制转换时,如:
A* ptr = (A*) myVoidPointer;
尝试类型转换操作的顺序总是先尝试使用static_cast
,然后再尝试使用reinterpret_cast
,这正是你想要的行为,因为reinterpret_cast
不能保证可移植性。
static_cast
... isn't necessarily guaranteed to work at runtime”是指,“你的程序可能会在后面崩溃。” 如果您从基类型向派生类型进行static_cast
,它将在运行时“工作”(即您不会收到异常或NULL
指针),但如果涉及多重继承,则结果可能指向错误的内存位置。 (有关更多详细信息,请参见此答案。)只有dynamic_cast
将使用RTTI进行运行时检查并在转换无效时优雅地失败。 - andrewtc这是一个棘手的问题。一方面,Konrad 对于 reinterpret_cast 的规范定义提出了很好的观点,尽管在实践中它可能执行相同的操作。另一方面,如果你正在转换指针类型(例如通过char* 在内存中进行索引),static_cast 将会生成编译器错误,你将被迫使用reinterpret_cast。
在实践中,我使用 reinterpret_cast,因为它更能描述强制类型转换的目的。当然,你可以为仅限于指针重新解释的不同运算符提供支持(以保证返回相同的地址),但标准中并没有这样的运算符。
reinterpret_cast
! - curiousguy你很可能是通过隐式转换获得了那个 void*
,因此应该使用 static_cast
,因为它最接近隐式转换。
使用static_cast
和reinterpret_cast
进行void*
类型的转换是相同的。请参考此链接中的答案。但通常情况下,更倾向于使用static_cast
,因为它更加精确且一般情况下(但不是在此特定情况下)更安全。
T* p1 = new T; const T* p2 = static_cast<const T*>(static_cast<void*>(p1)); bool b = p1 == p2; // b将具有true的值。
—end example]
reinterpret_cast:
一个对象指针可以被显式转换为不同类型的对象指针。当具有对象指针类型的prvalue v被转换为对象指针类型“指向cv T的指针”时,结果是static_cast<cv T*>(static_cast<cv void*>(v))
。reinterpret_cast T* from void*
等同于static_cast T* from void*
。static_cast
,因为关于reinterpret_cast和ISO标准的复杂性的可怕传说可能会让你无端地受到同行的抨击。
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Ru-pun
reinterpret_cast
可以用来将指针转换为 float
。转换的结构破坏程度越大,使用它的注意力就越多。char*
,我会使用 C 风格的转换方式,直到我们有了一些 reinterpret_pointer_cast
,因为它更弱且其他方式都不足够。float f = *reinterpret_cast<const float*>(&p);
。 - Ben Voigtfloat
,这是错误的。该表达式将 void **
强制转换为 const float *
,然后使用取消引用操作(这不是一个强制类型转换)将 const float *
转换为 float
。 - M.M使用 static_cast
进行类型转换。只有在极为罕见的情况下,当没有其他方法时才使用 reinterpret_cast
。
reinterpret_cast
会强制将 void*
转换为目标数据类型。它不保证任何安全性,因为底层对象可能是任何东西,所以你的程序可能会崩溃。
例如,你可以将 myclass*
强制转换为 void*
,然后使用 reinterpret_cast
将其转换为具有完全不同布局的 yourclass*
。
因此,最好和推荐使用 static_cast
。