当两个链接的static_cast可以完成它的工作时,为什么我们在C ++中使用reinterpret_cast?

时间:2011-02-17 06:43:07

标签: c++ casting reinterpret-cast static-cast

假设我想将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 casting for fstream read and write member functions

所以我的问题基本上是,

  • 为什么我们在C ++中有reinterpret_cast
  • 请告诉我一个例子,其中两个链式 static_cast肯定无法完成相同的工作?

7 个答案:

答案 0 :(得分:36)

reinterpret_cast可以做的事情,没有static_cast的序列可以做(所有来自C ++ 03 5.2.10):

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

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

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

  • 类型“指向类型为X的{​​{1}}成员的指针”的rvalue可以显式转换为类型为“T1成员{的指针”的rvalue {1}}“如果YT2都是函数类型或两种对象类型。

另外,来自C ++ 03 9.2 / 17:

  • 指向POD结构对象的指针(适当地使用T1转换)指向其初始成员(或者如果该成员是位字段,则指向它所在的单位),反之亦然。

答案 1 :(得分:15)

您需要reinterpret_cast来获取带有硬编码地址的指针(例如here):

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

您可能希望使用此类代码访问某些内存映射设备输入输出端口。

答案 2 :(得分: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'; }

答案 3 :(得分:5)

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

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

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

答案 4 :(得分:3)

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

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

从技术上讲,这两种选择并不相同。

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

答案 5 :(得分:0)

使用C Style铸造并不安全。它从不检查不同类型可以混合在一起。 C ++强制转换可帮助您确保按照相关对象(基于您使用的强制转换)完成类型转换。这是使用演员阵容比使用总是有害的传统C Style演员阵容更推荐的方式。

答案 6 :(得分:-1)

看,人们,你真的不需要reinterpret_cast,static_cast,甚至其他两个C ++样式转换(动态*和const)。

使用C样式转换更短,并且允许您执行四种C ++风格转换的所有操作。

anyType someVar = (anyOtherType)otherVar;

那么为什么要使用C ++风格的演员?可读性。其次:因为限制性更强的演员表允许更多的代码安全。

*好的,你可能需要动态