当两个链式static_cast可以完成它的工作时,为什么我们要在c++中重新解释?

时间:2022-09-11 12:06:31

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!):

假设我想将一个*转换为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

Both work fine.

工作很好。

//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!

甚至,这就做得够好了!

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

既然两个链式的static_cast可以完成它的工作,那么为什么要在c++中使用reinterpret_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?

有些人可能会认为这个主题是之前的主题的重复,如本文末尾列出的,但它不是。这些主题只在理论上讨论,但没有一个给出一个示例来说明为什么reintepret_cast是真正需要的,并且两个static_cast肯定会失败。我同意,一个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:

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

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

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

另外,请参见any_cast可能有用的情况:正确的fstream读写成员函数强制类型转换。

So my question basically is,

我的问题基本上是,

  • Why do we have reinterpret_cast in C++?
  • 为什么我们要在c++中重新解释?
  • Please show me even a single example where two chained static_cast would surely fail to do the same job?
  • 请给我看一个例子,两个链式的static_cast肯定不能执行相同的操作?

7 个解决方案

#1


35  

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

reinterpretation t_cast可以做的事情是static_cast序列所不能做的(都来自c++ 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.

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

  • 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.

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

Also, from C++03 9.2/17:

同时,从C + + 03 9.2/17:

  • 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.
  • 指向POD-struct对象的指针(适当地使用reinterpret_cast转换)指向它的初始成员(或者如果该成员是位域,那么指向它所在的单元),反之亦然。

#2


14  

You need reinterpret_cast to get a pointer with a hardcoded address (like here):

需要重新解释t_cast才能获得一个带有硬编码地址的指针(如这里):

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

you might want to have such code to get to some memory-mapped device input-output port.

您可能希望拥有这样的代码,以获得一些内存映射的设备输入-输出端口。

#3


6  

A concrete example:

一个具体的例子:

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'; }

#4


4  

Other than the practical reasons that others have given where there is a difference in what they can do it's a good thing to have because its doing a different job.

除了一些实际的原因,其他人给出了他们能做的不同的地方因为他们做了不同的工作。

static_cast is saying please convert data of type X to Y. reinterpret_cast is saying please interpret the data in X as a Y.

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

It may well be that the underlying operations are the same, and that either would work in many cases. But there is a conceptual difference between saying please convert X into a Y, and saying "yes I know this data is declared as a X but please use it as if it was really a Y".

很可能底层操作是相同的,而且在很多情况下都是一样的。但是在把X转换成Y和说"我知道这个数据被声明为X但请把它当做Y来使用"之间有概念上的区别。

#5


3  

As far as I can tell your choice 1 (two chained static_cast) is dreaded undefined behaviour. Static cast only guarantees that casting pointer to void * and then back to original pointer works in a way that the resulting pointer from these to conversions still points to the original object. All other conversions are UB. For pointers to objects (instances of the user defined classes) static_cast may alter the pointer value.

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

For the reinterpret_cast - it only alters the type of the pointer and as far as I know - it never touches the pointer value.

对于reinterpretation t_cast——它只改变指针的类型,就我所知——它从不触及指针值。

So technically speaking the two choices are not equivalent.

所以从技术上讲,这两个选项并不相等。

EDIT: For the reference, static_cast is described in section 5.2.9 of current C++0x draft (sorry, don't have C++03 standard, the draft I consider current is n3225.pdf). It describes all allowed conversions, and I guess anything not specifically listed = UB. So it can blow you PC if it chooses to do so.

编辑:为参考,static_cast在当前c++ 0x草稿的5.2.9节中描述(抱歉,没有c++ 03标准,我认为当前的草稿是n3225.pdf)。它描述了所有允许的转换,我想没有特别列出的东西= UB。因此,如果它选择这样做,它可以炸掉你的电脑。

#6


0  

Look, people, you don't really need reinterpret_cast, static_cast, or even the other two C++ styles casts (dynamic* and const).

听着,各位,实际上不需要reinterpretation t_cast、static_cast,甚至不需要其他两个c++风格的cast (dynamic*和const)。

Using a C style cast is both shorter and allows you to do everything the four C++-style cast let you do.

使用C样式的强制转换不仅更短,而且允许您执行c++样式的强制转换所允许的所有操作。

anyType someVar = (anyOtherType)otherVar;

So why use the C++-style casts? Readability. Secondly: because the more restrictive casts allow more code safety.

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

*okay, you might need dynamic

好的,你可能需要动态

#7


0  

Using of C Style casting is not safer. It never checks for different types can be mixed together. C++ casts helps you to make sure the type casts are done as per related objects (based on the cast you use). This is the more recommended way to use casts than using the traditional C Style casts that's always harmful.

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

#1


35  

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

reinterpretation t_cast可以做的事情是static_cast序列所不能做的(都来自c++ 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.

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

  • 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.

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

Also, from C++03 9.2/17:

同时,从C + + 03 9.2/17:

  • 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.
  • 指向POD-struct对象的指针(适当地使用reinterpret_cast转换)指向它的初始成员(或者如果该成员是位域,那么指向它所在的单元),反之亦然。

#2


14  

You need reinterpret_cast to get a pointer with a hardcoded address (like here):

需要重新解释t_cast才能获得一个带有硬编码地址的指针(如这里):

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

you might want to have such code to get to some memory-mapped device input-output port.

您可能希望拥有这样的代码,以获得一些内存映射的设备输入-输出端口。

#3


6  

A concrete example:

一个具体的例子:

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'; }

#4


4  

Other than the practical reasons that others have given where there is a difference in what they can do it's a good thing to have because its doing a different job.

除了一些实际的原因,其他人给出了他们能做的不同的地方因为他们做了不同的工作。

static_cast is saying please convert data of type X to Y. reinterpret_cast is saying please interpret the data in X as a Y.

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

It may well be that the underlying operations are the same, and that either would work in many cases. But there is a conceptual difference between saying please convert X into a Y, and saying "yes I know this data is declared as a X but please use it as if it was really a Y".

很可能底层操作是相同的,而且在很多情况下都是一样的。但是在把X转换成Y和说"我知道这个数据被声明为X但请把它当做Y来使用"之间有概念上的区别。

#5


3  

As far as I can tell your choice 1 (two chained static_cast) is dreaded undefined behaviour. Static cast only guarantees that casting pointer to void * and then back to original pointer works in a way that the resulting pointer from these to conversions still points to the original object. All other conversions are UB. For pointers to objects (instances of the user defined classes) static_cast may alter the pointer value.

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

For the reinterpret_cast - it only alters the type of the pointer and as far as I know - it never touches the pointer value.

对于reinterpretation t_cast——它只改变指针的类型,就我所知——它从不触及指针值。

So technically speaking the two choices are not equivalent.

所以从技术上讲,这两个选项并不相等。

EDIT: For the reference, static_cast is described in section 5.2.9 of current C++0x draft (sorry, don't have C++03 standard, the draft I consider current is n3225.pdf). It describes all allowed conversions, and I guess anything not specifically listed = UB. So it can blow you PC if it chooses to do so.

编辑:为参考,static_cast在当前c++ 0x草稿的5.2.9节中描述(抱歉,没有c++ 03标准,我认为当前的草稿是n3225.pdf)。它描述了所有允许的转换,我想没有特别列出的东西= UB。因此,如果它选择这样做,它可以炸掉你的电脑。

#6


0  

Look, people, you don't really need reinterpret_cast, static_cast, or even the other two C++ styles casts (dynamic* and const).

听着,各位,实际上不需要reinterpretation t_cast、static_cast,甚至不需要其他两个c++风格的cast (dynamic*和const)。

Using a C style cast is both shorter and allows you to do everything the four C++-style cast let you do.

使用C样式的强制转换不仅更短,而且允许您执行c++样式的强制转换所允许的所有操作。

anyType someVar = (anyOtherType)otherVar;

So why use the C++-style casts? Readability. Secondly: because the more restrictive casts allow more code safety.

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

*okay, you might need dynamic

好的,你可能需要动态

#7


0  

Using of C Style casting is not safer. It never checks for different types can be mixed together. C++ casts helps you to make sure the type casts are done as per related objects (based on the cast you use). This is the more recommended way to use casts than using the traditional C Style casts that's always harmful.

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