2016-09-29 57 views
3

我與這個龐大的開源C庫的工作,我經常發現類型之間的強制類型轉換看起來像這樣:是否有理由這樣做演員?

char *str; 
//some code 
unsigned char *str2 = *(unsigned char **) &str; 

我與它發揮各地,當我改變它看起來像

unsigned char *str2 = (unsigned char *) str; 

它似乎沒有問題的工作。請注意,這些強制轉換在整個代碼中很常見,在除unsigned char之外的其他類型中使用。

是否有理由通過引用和解引用來像這樣進行投射?

編輯:我不知道它是否相關,但此代碼應該是C89兼容。

編輯2:在發現一些具體實例

void *q = *(void **)(&p[i]); 

memento.c(線1122)

unsigned int rgba = *((unsigned int *)color); 

發現於:發現draw-paint.c(線332)

return cbz_strnatcmp(*(const char **)a, *(const char **)b); 
//both parameters are expected to be const char* 

在:mucbz.c(線73)

+2

你可以命名圖書館嗎? – 2501

+0

@ 2501它是[mupdf](http://mupdf.com/) – Cody

+1

你可以在實際的源代碼中發佈任何鏈接到這樣的例子嗎? – 2501

回答

3

所呈現的兩種替代方法中的每一種都涉及通過轉換將一種類型的指針轉​​換爲不同的指針類型。這是允許的,包括在C89中。在原始代碼中,轉換的指針被明確解除引用;在修改的代碼中,假定指針將在其他地方解除引用。在這些方面,這兩種變化執行完全相同種類的(允許的)行爲。

有一個技術差別,但是:第一替換導致char *類型的值經由unsigned char *類型的左值要被訪問時被讀取初始化表達式的值,以便被分配給str2。在標準的這個術語中,這兩個不是「兼容類型」,後者也不是與前者相對應的無符號類型(指針本身沒有簽名),也不是後者是字符類型或不同版本的前者或工會類型。因此訪問違反了俗稱爲「嚴格別名規則」的標準規定。

第二種選擇還轉換不兼容的指針類型之間,但是隨後的訪問它提供用於(並且第一替代還提供)由嚴格別名規則是允許的,這既是因爲字符類型可以別名任何東西,因爲unsigned char是對應於char的無符號類型,並且允許在這樣的對應類型之間混疊。

實際上,任何生產就緒的編譯器都不可能對原始代碼執行任何操作,而不是顯然期望的操作,但是修改後的代碼既清晰又更正確。

+1

將'char **'強制轉換爲'unsigned char **'是一種嚴格的別名衝突,因爲嚴格別名規則只允許'char *'類型來混淆所有內容?我認爲簽名對於嚴格的別名並不重要。 – yano

+1

@ yano,演員本身不是違規行爲,而且簽名不直接是問題。當訪問'*(unsigned char **)&str'的​​值時,違規來了,因爲該表達式是'unsigned char *'類型的左值,而它指定的對象的有效類型實際上是'char *'。字符類型允許別名,但不是字符類型,它們是(不兼容的)指針類型。此外,對方也不允許簽名或無符號類型。 –

+0

我需要再讀約10次。謝謝。 – yano

2

沒有理由像這樣施放。它的選擇問題。在

unsigned char *str2 = *(unsigned char **) &str; 

情況下,有一個不必要的非關聯化來獲得字符的地址s點。

使用

unsigned char *str2 = (unsigned char *)str; 

看上去幹淨給我。

+1

第一個是未定義的行爲(正如John Bollinger的回答所解釋的) –

+0

@ M.M謝謝。我以前沒有注意到。將刪除這個答案。 – haccks