当static_cast和reinterpret_cast具有相同的效果时,使用哪一个?

时间:2009-07-28 14:12:16

标签: c++ winapi casting

  

可能重复:
  Should I use static_cast or reinterpret_cast when casting a void* to whatever

通常,特别是在Win32编程中,需要从一个opaque类型转换为另一个opaque类型。例如:

 HFONT font = cast_here<HFONT>( ::GetStockObject( SYSTEM_FONT ) );

static_cast和reinterpret_cast在这里都适用,并且具有完全相同的效果,因为HFONT是一个指向伪结构的指针,该结构专门用于定义由GetStockObject()返回的HFONT和HGDIOBJ是一个void *指针。

哪一个 - static_cast或reinterpret_cast - 更好?

8 个答案:

答案 0 :(得分:15)

说明演员表具有相同的效果是不正确的。演员表演两件完全不同的事情:

  • static_cast<T>(x)表示将表达式x转换为T类型。
  • reinterpret_cast<T*>(&x)表示将内存位置'&amp; x'解释为T *

请考虑以下事项:

struct A1 { int a1; };
struct A2 { int a2; };
struct B : public A1, public A2 {};

void foo (A1 * a1, A2 * a2)
{
  B * b1_a1 = static_cast<B*> (a1);
  B * b2_a1 = reinterpret_cast<B*> (a1);
  B * b1_a2 = static_cast<B*> (a2);
  B * b2_a2 = reinterpret_cast<B*> (a2);

  std::cout << "b1_a1==b1_a2" << (b1_a1==b1_a2) << std::endl;
  std::cout << "b2_a1==b2_a2" << (b2_a1==b2_a2) << std::endl;
}

int main ()
{
  B b;
  foo (&b, &b);
}

此程序产生以下输出:

g++ -o t t.cc ; ./t
b1_a1==b1_a2: 1
b2_a1==b2_a2: 0

这显示static_casta2b2如何正确调整指针,使其指向b的开头,但reinterpret_cast执行了{{1}}不

答案 1 :(得分:12)

static_cast总是更可取,除非绝对必要,否则请避免reinterpret_cast

reinterpret_cast是最不安全的演员阵容。

this website关于在何时使用哪些演员表的更多信息。

答案 2 :(得分:4)

由于reinterpret_cast是实现定义的,我的经验法则是:“static_cast我可以,reinterpret_cast我必须”。

(其他演员除外)

答案 3 :(得分:2)

static_cast是首选。

来自Scott Meyers的更有效的C ++

  

此运算符[reinterpret_cast]用于执行类型   结果差不多的转换   总是实现定义的。作为一个   结果,reinterpret_casts很少   便携式的。

     

reinterpret_cast的最常见用法是在函数指针类型之间进行转换。

答案 4 :(得分:2)

我认为static_cast会更好。这里的another stack overflow post也有更多关于此的讨论。

答案 5 :(得分:2)

每个人都注意到reinterpret_cast&lt;&gt;比static_cast&lt;&gt;更危险 这是因为reinterpret_cast&lt;&gt;忽略所有类型信息,只是分配一个没有任何实际处理的新类型,因此完成的处理是实现定义的(尽管通常指针的位模式是相同的)。

每个人都没提到的是reinterpret_cast&lt;&gt;是一种记录您的程序的方法。它告诉有人阅读我们必须妥协的代码,因此我们最终会遇到危险的演员,并且当你搞乱这段代码时要小心。

使用reinterpret_cast&lt;&gt;在代码中突出显示这些危险区域。

从无效*中进行投射时,没有要使用的强制转换的类型信息 因此,您要么进行无效的强制转换,要么转换回原先转换为void *的原始类型。任何其他类型的强制转换都会导致一些未定义的行为。

这是使用reinterpret_cast&lt;&gt;的完美情况因为标准保证使用reinterpret_cast&lt;&gt;转换指向void *并返回其原始类型的指针将工作。并通过使用reinterpret_cast&lt;&gt;你指的是后来出现的人类,这里发生了一些不好的事情。

答案 6 :(得分:1)

你应该真的做任何win32文档所说的正确的事情。这是最有可能工作的,最有可能是前向兼容的,除非我的作者完全无能为力。

更新:我查了一下。 Win32文档使用C样式转换。在这种情况下,C ++定义了一个C样式转换来执行static cast。所以正确的答案是:使用static_cast。或者是C风格演员,但他们通常最好避免使用。

答案 7 :(得分:0)

我的正常建议:

reinterpret_cast<>仅用作最后的手段。你告诉编译器要抛弃所有的注意事项,“删除所有的安全设备”,并且相信你的话,它确实是好的,无论编译器知道什么代码。只有在没有别的办法可以使用时才应该使用它。

有些地方可能会产生相同的效果 IF 您的代码是正确的。如果你最终做出更改并引入错误并且演员阵容不再正确,static_cast<>可能会抓住它,但reinterpret_cast<>肯定不会。

在这个非常特殊的场景中,最后一个参数并没有那么多:API正在强加你的语义;他们的语义很好理解;你正在施放(无效*)。

不过,我会使用static_cast<>,并将reinterpret_cast<>留给真正非凡环境迫使我绕过类型安全的地方。由于API的C兼容性,这是一个“正常”强制转换。

(有关static_cast&lt;&gt;和reinterpret_cast&lt;&gt;)

之间差异的更多详细信息,另请参阅my post here