2008-12-04 62 views
12

如何在不丟失編譯器內部數據的情況下進行類型轉換?C/C++編譯器如何處理具有不同值範圍的類型之間的類型轉換?

例如:

int i = 10; 
UINT k = (UINT) k; 

float fl = 10.123; 
UINT ufl = (UINT) fl; // data loss here? 

char *p = "Stackoverflow Rocks"; 
unsigned char *up = (unsigned char *) p; 

編譯器如何處理這種類型的類型轉換的?顯示位的低級示例將受到高度讚賞。

回答

18

那麼,首先注意,演員陣容是明確要求將一種類型的值轉換爲另一種類型的值。劇組也會一直產生一個新的對象,這是一個臨時由演員操作員返回的對象。但是,轉換爲引用類型不會創建新對象。該值引用的對象被重新解釋爲不同類型的引用。

現在你的問題。請注意,有兩種主要類型的轉換:

  • 促銷:這種類型可以被認爲從可能更窄類型更廣泛的類型轉換。從char到int,從短到int,從float到double都是促銷活動。
  • 轉換:這些允許從long轉換爲int,int轉換爲unsigned int等等。原則上它們會導致信息的丟失。例如,如果將-1分配給無符號類型的對象,會發生什麼規則。在某些情況下,錯誤的轉換可能導致未定義的行爲。如果將大於浮點數可以存儲到浮點數的double賦值爲double,則行爲未定義。

讓我們看看你的石膏:

int i = 10; 
unsigned int k = (unsigned int) i; // :1 

float fl = 10.123; 
unsigned int ufl = (unsigned int) fl; // :2 

char *p = "Stackoverflow Rocks"; 
unsigned char *up = (unsigned char *) p; // :3 
  1. 這就讓人產生轉換的情況發生。沒有數據丟失發生,因爲保證10被存儲在unsigned int。如果整數是負數,則該值基本上將包含無符號整數的最大值(請參閱4.7/2)。
  2. 10.123被截斷爲10.這裏,它確實顯然導致信息丟失。當10符合unsigned int時,行爲就被定義了。
  3. 這實際上需要更多的關注。首先,從字符串文字到char*有一個不贊成的轉換。但我們在這裏忽略它。 (見here)。更重要的是,如果轉換爲無符號類型會發生什麼?實際上,這個結果沒有被指定爲每5.2.10/7(注意,這個演員的語義與在這種情況下使用reinterpret_cast相同,因爲這是唯一能夠做到的C++演員):

指向對象的指針可以顯式轉換爲指向 指針的不同類型的對象。除了將「指向T1的指針」類型的右值轉換爲類型「指向T2的指針」(其中T1和T2是對象類型,並且T2的對齊要求不比T1更嚴格)並返回到其原始類型原始指針值,這種指針轉換的結果是未指定的。

所以你只有在你再次回到char *後才能使用指針。

+0

注意:這隻適用於C++,不適用於C – Stargateur 2017-01-15 04:46:32

5

C和C++中的「Type」是在編譯器中處理變量時分配給變量的屬性。該屬性在運行時不再存在,除了C++中的虛函數/ RTTI。

編譯器使用變量類型來確定很多事情。例如,在將float分配給int時,它將知道它需要轉換。這兩種類型可能都是32位,但含義不同。 CPU可能有一條指令,否則編譯器會知道調用一個轉換函數。即 & __stack[4] = float_to_int_bits(& __stack[0])

從char *到unsigned char *的轉換甚至是simpeler。這只是一個不同的標籤。在位級別,p和up是相同的。編譯器只需要記住* p需要符號擴展,而*不需要。

8

在你的例子中的兩個C風格演員是不同種類的演員。在C++中,你通常寫他們

unsigned int uf1 = static_cast<unsigned int>(fl); 

unsigned char* up = reinterpret_cast<unsigned char*>(p); 

第一執行算術鑄造,其截斷浮點數,所以有數據丟失。

第二個不更改數據 - 它只是指示編譯器將指針視爲不同的類型。需要注意這種鑄造:它可能是非常危險的。

1

根據它們是什麼,演員表示不同的事情。它們可以只是一種數據類型的重新編譯,而不會改變所表示的位(整數類型和指針之間的大多數轉換是這樣的),或者甚至不保留長度的轉換(例如,在大多數編譯器之間的double和int之間) 。在很多情況下,演員的意思是沒有指定的,這意味着編譯器必須做一些合理的事情,但不必準確記錄。

演員甚至不需要導致可用值。類似 char * cp; float * fp; cp = malloc(100); fp = (float *)(cp + 1); 幾乎肯定會導致浮點指針錯位,如果程序嘗試使用它,則會在某些系統上崩潰該程序。