应该在将`void*`转换为任何其他类型时使用`static_cast`还是`reinterpret_cast`?

18 浏览
0 Comments

应该在将`void*`转换为任何其他类型时使用`static_cast`还是`reinterpret_cast`?

static_castreinterpret_cast 在将 void* 转换为另一个指针类型时似乎都可以正常工作。是否有一个更好的理由来支持其中一个?

0
0 Comments

在C++中,当我们需要将一个void指针转换为其他类型时,我们可以使用static_cast或reinterpret_cast来进行转换。然而,选择使用哪个转换操作符可能会成为一个棘手的问题。

在使用static_cast时,如果我们尝试将void指针转换为其他指针类型(例如通过char*在内存中进行索引),编译器会生成一个错误,并强制我们使用reinterpret_cast进行转换。因此,当我们需要进行指针类型之间的转换时,static_cast可能不是一个可行的选择。

相比之下,我更倾向于使用reinterpret_cast,因为它更能描述转换操作的意图。虽然可以为指针重新解释设计一个不同的操作符(它保证返回相同的地址),但标准中并没有这样的操作符。

然而,有人提出了一个问题,即reinterpret_cast是否保证返回相同的地址。根据标准,reinterpret_cast并不保证返回相同的地址。它只保证如果我们将一个类型重新解释为另一个类型,然后再重新解释回来,我们将得到与开始时相同的地址。

当我们需要将void指针转换为其他类型时,我们可以使用static_cast或reinterpret_cast。如果我们需要进行指针类型之间的转换,我们可能需要使用reinterpret_cast。然而,需要注意的是,reinterpret_cast并不保证返回相同的地址,只是在特定情况下保证返回相同的地址。

代码示例:

void* ptr = nullptr;
int* intPtr = reinterpret_cast(ptr); // 使用reinterpret_cast将void指针转换为int指针类型

0
0 Comments

当将一个`void*`指针转换为其他类型的指针时,应该使用`static_cast`还是`reinterpret_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`。如果你事先知道转换在运行时会成功,并且向编译器传达“我知道这可能不起作用,但至少它是有意义的,并且我有理由相信它在运行时会正确执行正确的操作”,那么`static_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`... 在运行时不一定能保证工作”的意思是,“你的程序可能在后期崩溃”。如果你从基类型`static_cast`到派生类型,它在运行时将“工作”(即你将不会得到异常或`NULL`指针),但结果可能指向错误的内存位置(如果涉及多继承)。只有`dynamic_cast`会进行运行时检查(使用RTTI),并在转换无效时优雅地失败。

对于将`void*`转换为其他类型的指针,应该优先使用`static_cast`,而不是`reinterpret_cast`,以确保类型转换的安全性和可移植性。

0
0 Comments

问题的出现原因是有一种误解,即使用reinterpret_cast比使用static_cast更好,因为它意味着"完全忽略类型安全性,只是从A转换为B"。然而,这实际上并没有描述reinterpret_cast的效果。reinterpret_cast有多种含义,对于所有这些含义,都有一个共同点,即"reinterpret_cast的映射是由实现定义的"。但是,在将void*转换为T*的特定情况下,映射是完全由标准定义的,即给予一个无类型指针赋予一个类型,而不改变其地址。这是更倾向于使用static_cast的原因之一。

另外,更重要的是,每次使用reinterpret_cast都是非常危险的,因为它可以将任何东西转换为任何其他东西(对于指针而言),而static_cast则更加限制,因此提供了更好的保护水平。这已经帮助我避免了一些错误,其中我无意中尝试将一个指针类型强制转换为另一个指针类型。

解决方法是使用static_cast来将void*转换为特定类型的指针。static_cast是最狭窄的转换,恰好描述了在这里进行的转换。它提供了更好的类型安全性,并且在转换指针类型时更加受限制,因此提供了更高的保护水平。

0