当两个链接的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函数的指针。
-
如果
T1
和T2
都是函数types或两个对象types,则可以将types“指向T1
types的X
的成员的指针”的右值显式地转换为types“指向T2
types的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风格演员更受推荐的方式来使用演员,这是总是有害的。