混跡C++ 之reinterpret_cast和static_cast
reinterpret_cast運算子是用來處理無關型別之間的轉換;它會產生一個新的值,
這個值會有與原始引數(expressoin)有完全相同的位元位。
IBM的C++指南裡倒是明確告訴了我們reinterpret_cast可以,或者說應該在什麼地方用來作為轉換運算子:
- 從指標型別到一個足夠大的整數型別
- 從整數型別或者列舉型別到指標型別
- 從一個指向函式的指標到另一個不同型別的指向函式的指標
- 從一個指向物件的指標到另一個不同型別的指向物件的指標
- 從一個指向類函式成員的指標到另一個指向不同型別的函式成員的指標
- 從一個指向類資料成員的指標到另一個指向不同型別的資料成員的指標
總結來說:reinterpret_cast用在任意指標(或引用)型別之間的轉換;
以及指標與足夠大的整數型別之間的轉換;從整數型別(包括列舉型別)到指標型別,無視大小。
(所謂"足夠大的整數型別",取決於作業系統的引數,如果是32位的作業系統,就需要整形(int)以上的;
如果是64位的作業系統,則至少需要長整形(long)。具體大小可以通過sizeof運算子來檢視)。
和MSDN的Visual C++也都指出:錯誤的使用reinterpret_cast很容易導致程式的不安全,只有將轉換後的型別
值轉換回到其原始型別,這樣才是正確使用reinterpret_cast方式。
這樣說起來,reinterpret_cast轉換成其它型別的目的只是臨時的隱藏自己的什麼(做個臥底?),
要真想使用那個值,還是需要讓其露出真面目才行。那到底它在C++中有其何存在的價值呢?
// expre_reinterpret_cast_Operator.cpp
// compile with: /EHsc
#include <iostream>
// Returns a hash code based on an address
unsigned short Hash( void *p ) {
unsigned int val = reinterpret_cast <unsigned int>( p );
return ( unsigned short )( val ^ (val >> 16));
}
using namespace std;
int main() {
int a[20];
for ( int i = 0; i < 20; i++ )
cout << Hash( a + i ) << endl;
}
對整數的操作顯然要對地址操作更方便。在集合中存放整形數值,也要比存放地址更具有擴充套件性
(當然如果存void *擴充套件性也是一樣很高的),唯一損失的可能就是存取的時候整形和地址的轉換
(這完全可以忽略不計)。
IBM的C++指南指出:reinterpret_cast不能像const_cast那樣去除const修飾符。
相關連結:http://www.cnblogs.com/ider/archive/2011/07/30/cpp_cast_operator_part3.html
一段程式碼示例:
#include <iostream>//www.fishc.com
int main()
{
const unsigned short ITEMS = 5;
int intArray[ITEMS] = {1,2,3,4,5};
char charArray[ITEMS] = {'F','i','s','h','C'};
int *intPtr = intArray;
char *charPtr = charArray;
std::cout << "整型陣列輸出:"<< '\n';
for(int i=0; i<ITEMS; i++)
{
std::cout << *intPtr << "at" <<reinterpret_cast<unsigned long>(intPtr)<<'\n';
//std::cout << *intPtr << "at" <<static_cast<unsigned int*>(intPtr)<<'\n';
std::cout << *intPtr << "at" <<intPtr<<'\n';
std::cout<<"-------------------------------"<<'\n';
intPtr++;
}
std::cout << "字元型型陣列輸出:" << '\n';
for(int i=0; i<ITEMS; i++)
{
std::cout << *charPtr << "at" <<reinterpret_cast<unsigned long>(charPtr) <<'\n';
std::cout << *charPtr << "at" <<charPtr <<'\n';
執行結果:
整型陣列輸出: 1at3214992192 1at0xbfa0e340 ------------------------------- 2at3214992196 2at0xbfa0e344 ------------------------------- 3at3214992200 3at0xbfa0e348 ------------------------------- 4at3214992204 4at0xbfa0e34c ------------------------------- 5at3214992208 5at0xbfa0e350 ------------------------------- 字元型型陣列輸出: Fat3214992215 FatFishC ------------------------------- iat3214992216 iatishC ------------------------------- sat3214992217 satshC ------------------------------- hat3214992218 hathC ------------------------------- Cat3214992219 CatC ------------------------------- |
注意:在轉換前後沒有數位損失。 |
static_cast
轉自百科名片
該運算子把expression轉換為type-id型別,但沒有執行時型別檢查來保證轉換的安全性。它主要有如下幾種用法:
①用於類層次結構中基類(父類)和派生類(子類)之間指標或引用的轉換。
進行上行轉換(把派生類的指標或引用轉換成基類表示)是安全的;
進行下行轉換(把基類指標或引用轉換成派生類表示)時,由於沒有動態型別檢查,所以是不安全的。
②用於基本資料型別之間的轉換,如把int轉換成char,把int轉換成enum。這種轉換的安全性也要開發人員來保證。
③把空指標轉換成目標型別的空指標。
④把任何型別的表示式轉換成void型別。
注意:static_cast不能轉換掉expression的const、volatile、或者__unaligned屬性。
C++中static_cast和reinterpret_cast的區別
C++primer第五章裡寫了編譯器隱式執行任何型別轉換都可由static_cast顯示完成;
reinterpret_cast通常為運算元的位模式提供較低層的重新解釋
1、C++中的static_cast執行非多型的轉換,用於代替C中通常的轉換操作。因此,被做為隱式型別轉換使用。
比如:
int i;
float f = 166.71;
i = static_cast<int>(f);
此時結果,i的值為166。
2、C++中的reinterpret_cast主要是將資料從一種型別的轉換為另一種型別。
所謂“通常為運算元的位模式提供較低層的重新解釋”也就是說將資料以二進位制存在形式的重新解釋
比如:
int i;
char *p = "This is a example.";
i = reinterpret_cast<int>(p);
此時結果,i與p的值是完全相同的。
reinterpret_cast的作用是說將指標p的值以二進位制(位模式)的方式被解釋為整型,並賦給i,//i 也是指標,整型指標