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

2021-12-31 00:00:00 casting c++ static-cast reinterpret-cast

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

Say I want to cast A* to char* and vice-versa, we have two choices (I mean, many of us think we've two choices, because both seems to work! Hence the confusion!):

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

即使这样也能正常工作!

Even this works fine!

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

So why do we have reinterpret_cast in C++ when two chained static_cast can do its job?

你们中的一些人可能认为这个主题是之前的主题的重复,例如在这篇文章的底部列出,但事实并非如此.这些主题只是理论上讨论,但他们都没有给出一个例子来说明为什么确实需要reintepret_cast,以及两个 static_cast 会肯定失败.我同意,一个 static_cast 会失败.但是两个呢?

Some of you might think this topic is a duplicate of the previous topics such as listed at the bottom of this post, but it's not. Those topics discuss only theoretically, but none of them gives even a single example demonstrating why reintepret_cast is really needed, and two static_cast would surely fail. I agree, one static_cast would fail. But how about two?

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

If the syntax of two chained static_cast looks cumbersome, then we can write a function template to make it more programmer-friendly:

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

然后我们可以这样使用:

And then we can use this, as:

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 可能有用的这种情况:fstream 读写成员函数的正确转换.

Also, see this situation where any_cast can be useful: Proper casting for fstream read and write member functions.

所以我的问题基本上是,

So my question basically is,

  • 为什么我们在 C++ 中有 reinterpret_cast?
  • 请给我举一个例子,其中两个链式 static_cast 肯定无法完成相同的工作?
  • Why do we have reinterpret_cast in C++?
  • Please show me even a single example where two chained static_cast would surely fail to do the same job?
  • 使用哪个演员表;static_cast 还是 reinterpret_cast?
  • 演员从 Void* 到 TYPE*?? : static_cast 或 reinterpret_cast

推荐答案

有些事情 reinterpret_cast 可以做到而 static_cast 的序列无法做到(全部来自 C++03 5.2.10):

There are things that reinterpret_cast can do that no sequence of static_casts can do (all from C++03 5.2.10):

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

  • A pointer can be explicitly converted to any integral type large enough to hold it.

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

A value of integral type or enumeration type can be explicitly converted to a pointer.

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

A pointer to a function can be explicitly converted to a pointer to a function of a different type.

类型为 T1 的指向 X 成员的指针"类型的右值可以显式转换为指向 X 成员的指针"类型的右值>Y of type T2" 如果 T1T2 都是函数类型或都是对象类型.

An rvalue of type "pointer to member of X of type T1" can be explicitly converted to an rvalue of type "pointer to member of Y of type T2" if T1 and T2 are both function types or both object types.

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

Also, from C++03 9.2/17:

  • 一个指向 POD 结构对象的指针,使用 reinterpret_cast 适当转换,指向它的初始成员(或者如果该成员是位域,则指向它所在的单元)反之亦然.
  • A pointer to a POD-struct object, suitably converted using a reinterpret_cast, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa.

相关文章