2010-09-16 111 views
2

有人可以解釋這對我說:簡單的C++指針鑄造

char* a; 
unsigned char* b; 

b = a; 
// error: invalid conversion from ‘char*’ to ‘unsigned char*’ 

b = static_cast<unsigned char*>(a); 
// error: invalid static_cast from type ‘char*’ to type ‘unsigned char*’ 

b = static_cast<unsigned char*>(static_cast<void*>(a)); 
// everything is fine 

做什麼投2和3之間的區別?如果3的方法用於其他(更復雜的)類型,那麼是否存在任何缺陷?

[編輯] 由於一些不良提到設計等......

這個簡單的例子來自圖像庫,它給我的指針圖像數據char*。顯然圖像強度總是正面的,所以我需要將其解釋爲unsigned char數據。

+0

我不同意你的編輯聲明。如果你給了一個char數組,那麼它就是一個char數組。類型很強大,真正用C++,而且你在做C雜技。在編譯器告訴你錯誤的大部分時間中,絕大多數時間是錯誤的。 – 2010-09-16 11:31:41

+0

如果在某個時刻你確實需要unsigned char,你可以簡單地做到這一點,但在你真正需要的時刻:'int i = 65; unsigned int j = i;'這會編譯,因爲它是合法的,你總是可以合法地將char存儲在一個無符號字符中。 – 2010-09-16 11:46:53

+0

那麼,如果另一個庫需要正確的'unsigned char *':D。你會寫一個循環,並將所有的值複製到一個新的數組? – tauran 2010-09-16 12:04:12

回答

5

static_cast<void*>殲滅類型檢查的目的,就像你說的那樣,現在它指向「你不知道類型的東西」。然後編譯器必須相信你,當你說你的新void*然後static_cast<unsigned char*>他只會嘗試做他的工作,因爲你明確要求

如果您確實必須在此處使用演員表(因爲在此處顯示設計問題顯而易見),您最好使用reinterpret_cast<>

2

C++試圖對C進行類型轉換比限制性更強,所以它不允許你使用static_cast(注意你將失去標誌信息)將字符轉換爲無符號字符。然而,類型void*是特殊的,因爲C++不能做出任何假設,並且必須依賴編譯器告訴它確切的類型(因此第三次投射)。

至於你的第二個問題,當然有很多使用void*。通常,您不必使用它,因爲C++類型的系統,模板等足夠豐富,不必依賴於「未知類型」。另外,如果你真的需要使用它,你必須非常小心,從void*控制插入和獲得的類型是真的相同(例如,不指向子類等)

1

差異在2和3之間是3,你明確告訴編譯器停止檢查你通過轉換爲void *。如果使用3的方法,幾乎​​所有不是直接原始整數類型的東西,都會調用未定義的行爲。無論如何,你可能會在#3中調用未定義的行爲。如果它不隱式投射,那麼除非你真的知道發生了什麼,否則幾乎肯定是一個壞主意,如果你將一個void *轉換回不是原始類型的東西,你將會得到未定義的行爲。

2

指針之間的static_cast只有在指針之一爲空或者在類的對象之間進行轉換時纔會正確工作,其中一個類由另一個類繼承。

+0

+1不錯而且很短。另外,值得一提的是'static_cast'不能將const強制轉換。 – sellibitze 2010-09-16 11:12:30

+1

該標準允許您使用static_cast從'T *'轉換爲'void *'並返回到'T *'。從'void *'投射到不同於原始指針的類型的結果在標準中是未定義的。 – 2010-09-16 11:24:29

0

施放之間的指針需要reinterpret_cast,與void*除外:

從任何指針類型轉換對void*是隱含的,所以你並不需要顯式轉換:

char* pch; 
void* p = pch; 

void*施放到任何其他指針只需要一個static_cast

unsigned char* pi = static_cast<unsigned char*>(p); 
4

您的第三種方法是可行的,因爲C++允許通過static_cast(並再次返回)將void指針傳送到T*,但出於安全原因,其他指針類型更受限制。 charunsigned char是兩種不同的類型。這需要reinterpret_cast

+2

+1另外請注意,雖然編譯器會接受代碼,並且在所有場景中我都能想到它會起作用,但標準允許'static_cast'爲'void *'並返回到相同的類型,這不是您正在做的。這個答案是正確的:你應該使用'reinterpret_cast'明確。 – 2010-09-16 11:21:29

+0

reinterpret_cast非常危險,它不是跨平臺的。 – zaynyatyi 2010-09-16 11:23:55

+1

reinterpret轉換在這裏是完全合適的......(編輯)的問題表明這是一個解決方案,它實際上提供了無符號的char值,但在它的接口中錯誤地稱它們爲char。有數十億行C代碼充斥着非常好的演員表,你只需要清楚地理解這兩者的數據類型,以及你要求編譯器做什麼。 – 2010-09-16 11:36:13

0

要小心,當你投射到void *時,你會失去任何類型的信息。

你所要做的是錯誤的,錯誤的,容易出錯和誤導的。這就是爲什麼compilator返回編譯錯誤:-)

一個簡單的例子

char* pChar = NULL; // you should always initalize your variable when you declare them 
unsigned char* pUnsignedChar = NULL; // you should always initalize your variable when you declare them 

char aChar = -128; 
pChar = &aChar; 
pUnsignedChar = static_cast<unsigned char*>(static_cast<void*>(pChar)); 

那時,雖然pUnsignedChar == pChar nonethless我們有*pUnsignedChar == 255*pChar == -128

我確實認爲這是不好的笑話,因此代碼不好。

+0

嗯,但這正是演員的目的:),請參閱我的編輯 – tauran 2010-09-16 11:18:04

+0

「reinterpret_cast」的用途與您所做的相同,只有在您知道對象的類型後才能使用。在你的例子中,你顯然分享信息。既然你問這種類型的問題,那麼你顯然是C++的初學者,否則你應該已經知道'reinterpret_cast'只有在真正瞭解你所做的事情時才能用在極限上。 – 2010-09-16 11:22:15

+0

你寫作好像是一個初學者是一件壞事... – tauran 2010-09-16 11:23:52