44

假设我想投到A*char*反之亦然,我们有两个选择(我的意思是,我们中的许多人认为我们有两个选择,因为两者似乎都有效!因此混乱!):

struct A
{
    int age;
    char name[128];
};

A a;
char *buffer = static_cast<char*>(static_cast<void*>(&a)); //choice 1
char *buffer = reinterpret_cast<char*>(&a); //choice 2

两者都工作正常。

//convert back
A *pA = static_cast<A*>(static_cast<void*>(buffer)); //choice 1
A *pA = reinterpret_cast<A*>(buffer); //choice 2

即使这样也能正常工作!

那么为什么我们reinterpret_cast在 C++ 中有两个链式 static_cast可以完成它的工作呢?

你们中的一些人可能会认为这个主题与之前的主题重复,例如本文底部列出的主题,但事实并非如此。这些主题仅在理论上进行讨论,但没有一个给出一个例子来说明为什么reintepret_cast真的需要,而且两个 static_cast肯定失败。我同意,一个 static_cast 会失败。但是两个呢?

如果两个链式的语法static_cast看起来很繁琐,那么我们可以编写一个函数模板,使其对程序员更友好:

template<class To, class From>
To any_cast(From v)
{
    return static_cast<To>(static_cast<void*>(v));
}

然后我们可以使用它,如:

char *buffer = any_cast<char*>(&a); //choice 1
char *buffer = reinterpret_cast<char*>(&a); //choice 2

//convert back
A *pA = any_cast<A*>(buffer); //choice 1
A *pA = reinterpret_cast<A*>(buffer); //choice 2

另外,请参阅这种any_cast可能有用的情况:Proper cast for fstream read and write member functions

所以我的问题基本上是,

  • 为什么我们有reinterpret_castC++?
  • 请给我看一个例子,两个链式 static_cast肯定不能做同样的工作?

4

7 回答 7

36

有一些sreinterpret_cast序列static_cast无法做到的事情(全部来自 C++03 5.2.10):

  • 指针可以显式转换为任何大到足以容纳它的整数类型。

  • 整数类型或枚举类型的值可以显式转换为指针。

  • 指向函数的指针可以显式转换为指向不同类型函数的指针。

  • 如果和都是函数类型或都是对象类型,则“指向类型成员的指针”X类型T1的右值可以显式转换为“指向类型成员的指针”类型的右值。YT2T1T2

此外,从 C++03 9.2/17 开始:

  • 一个指向 POD 结构对象的指针,使用 a 进行适当转换reinterpret_cast,指向它的初始成员(或者如果该成员是位字段,则指向它所在的单元),反之亦然。
于 2011-02-17T06:52:20.087 回答
15

您需要reinterpret_cast获得一个带有硬编码地址的指针(如这里):

int* pointer = reinterpret_cast<int*>( 0x1234 );

您可能希望有这样的代码来访问一些内存映射设备的输入输出端口。

于 2011-02-17T06:46:01.027 回答
6

一个具体的例子:

char a[4] = "Hi\n";
char* p = &a;

f(reinterpret_cast<char (&)[4]>(p));  // call f after restoring full type
      // ^-- any_cast<> can't do this...

// e.g. given...
template <typename T, int N>   // <=--- can match this function
void f(T (&)[N]) { std::cout << "array size " << N << '\n'; }
于 2011-02-17T07:33:24.640 回答
6

除了其他人给出的实际原因之外,他们可以做的事情有所不同,这是一件好事,因为它做的是不同的工作。

static_cast 表示请将 X 类型的数据转换为 Y。 reinterpret_cast 表示请将 X 中的数据解释为 Y。

很可能底层操作是相同的,并且在许多情况下都可以工作。但是说请将 X 转换为 Y 和说“是的,我知道这个数据被声明为 X 但请像真的是 Y 一样使用它”之间存在概念上的区别。

于 2011-02-17T08:29:35.990 回答
3

据我所知,您的选择 1(两个链式 static_cast)是可怕的未定义行为。静态转换仅保证将指针转换为 void * 然后返回到原始指针的工作方式是,从这些到转换的结果指针仍指向原始对象。所有其他转换都是 UB。对于指向对象(用户定义类的实例)的指针,static_cast 可能会改变指针值。

对于 reinterpret_cast - 它只改变指针的类型,据我所知 - 它从不触及指针值。

所以从技术上讲,这两种选择并不等同。

编辑:作为参考,static_cast 在当前 C++0x 草案的第 5.2.9 节中进行了描述(对不起,没有 C++03 标准,我认为当前的草案是 n3225.pdf)。它描述了所有允许的转换,我猜任何没有特别列出的东西 = UB。因此,如果它选择这样做,它可能会炸毁你的 PC。

于 2011-02-17T09:35:26.150 回答
0

使用 C 风格铸造并不安全。它从不检查不同的类型是否可以混合在一起。C++ 转换可帮助您确保类型转换是根据相关对象完成的(基于您使用的转换)。与使用总是有害的传统 C 样式类型转换相比,这是更推荐的使用类型转换的方法。

于 2014-10-11T06:59:31.757 回答
-1

看,伙计们,你真的不需要 reinterpret_cast、static_cast 甚至其他两种 C++ 样式转换(dynamic* 和 const)。

使用 C 样式转换既短又允许您执行四种 C++ 样式转换让您做的所有事情。

anyType someVar = (anyOtherType)otherVar;

那么为什么要使用 C++ 风格的强制转换呢?可读性。其次:因为更严格的强制转换允许更多的代码安全。

*好的,你可能需要动态

于 2011-02-17T07:04:40.197 回答