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

假设我想把A*char* ,反之亦然,我们有两个select(我的意思是,我们中的很多人认为我们有两个select, 因为两者似乎都起作用了,所以混淆了):

 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 

即使这个工作正常!

那么为什么当两个链接的 static_cast可以完成它的工作时,我们在C ++中有reinterpret_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可以是有用的: 适当的铸造fstream读取和写入成员函数 。

所以我的问题基本上是,

  • 为什么我们在C ++中使用reinterpret_cast
  • 请给我看一个例子,其中两个链接的 static_cast肯定无法做同样的工作?

  • 哪个可以使用; static_cast或reinterpret_cast?
  • 从Void *投射到TYPE *:static_cast或reinterpret_cast

有些东西reinterpret_cast可以做static_cast没有序列可以做的(全部来自C ++ 03 5.2.10):

  • 指针可以显式转换为任何足够大的整数types来保存它。

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

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

  • 如果T1T2都是函数types或两个对象types,则可以将types“指向T1types的X的成员的指针”的右值显式地转换为types“指向T2types的Y的成员的指针”的右值。

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

  • 指向POD-struct对象的指针,使用reinterpret_cast适当转换,指向其初始成员(或者如果该成员是位字段,则指向其驻留的单元),反之亦然。

你需要reinterpret_cast来获得一个硬编码地址的指针(像这里 ):

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

你可能希望有这样的代码到达一些内存映射设备的input输出端口。

一个具体的例子:

 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... // eg given... template <typename T, int N> // <=--- can match this function void f(T (&)[N]) { std::cout << "array size " << N << '\n'; } 

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

static_cast是说请将X型的数据转换为Y. reinterpret_cast是说请把X中的数据解释为Y.

基本的操作可能是一样的,而且在很多情况下都可以工作。 但是,在说X请转换成Y时,有一个概念上的区别,并且说“是的,我知道这个数据被声明为X,但是请使用它,好像它真的是Y”。

据我可以告诉你的select1(两个链式static_cast)是可怕的未定义的行为。 静态转换只能保证将指针指向void *,然后返回原始指针,从而使指向这些转换的指针仍然指向原始对象。 所有其他转换都是UB。 对于指向对象的指针(用户定义的类的实例),static_cast可能会改变指针的值。

对于reinterpret_cast – 它只会改变指针的types,据我所知,它不会触及指针值。

所以从技术上讲这两个select是不相同的。

编辑:作为参考,static_cast在当前C ++ 0x草案(对不起,没有C ++ 03标准,我认为当前的草案是n3225.pdf)第5.2.9节中描述。 它描述了所有允许的转换,我猜没有具体列出的任何东西= UB。 所以如果select这样的话,它可能会让你的电脑受到打击。

看,人们,你真的不需要reinterpret_cast,static_cast,甚至其他两个C ++风格强制转换(dynamic*和常量)。

使用C风格转换更短,并允许你做四件C ++风格的转换,让你做。

 anyType someVar = (anyOtherType)otherVar; 

那么为什么要使用C ++风格的强制转换呢? 可读性。 其次:因为限制性较强的演员可以提供更多的代码安全性。

*好的,你可能需要dynamic的

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