ANSI C中的整型升級
char,short int或者int型位段(bit-field),包括它們的有符號或無符號變型,以及枚舉類型,可以使用在需要int或unsigned int的運算式中,如果int可以完整地表示源類型的所有值,那麼該類型的值就轉換為int,否則轉換為unsigned int。
ANSI C中的尋常算術轉換
當執行算術運算時,運算元的類型如果不同,就會發生轉換。
資料類型一般朝著浮點精度更高、長度更長的方向轉換,整型數如果轉換為signed不會丟失資訊,就轉換為signed,否則就轉換為unsigned。
這個稱為值保留(value preserving)原則,與K&R C所採用的無符號保留(unsigned preserving)原則不同。
浮點類:
如果一個運算元的類型是long double,那麼另一個運算元無論是什麼類型都將被轉換成long double。
如果兩個運算元都不是long double型,那麼當其中一個運算元的類型是double型,則另一個就將被轉換成double 型。
如果兩個運算元都不是double型,而其中一個運算元是float型,則另一個被轉換成float型。
注意:double和float都不可用unsigned,short修飾,另外float還不可用long修飾
整形類規:
否則,兩個運算元都不是三種浮點類型之一,它們一定是某種整實值型別。在確定共同的目標提升類型之前,編譯器將在所有小於int的整實值型別上施加一個被稱為整值提升(integral promotion)的過程。在進行整值提升時,類型(char、signed char、unsigned char和short、int)都被提升為類型int。如果機器上的int型足夠表示所有unsigned、shoft型的值(這通常發生在short用半個字表示,而int用一個字表示的情況下),則unsigned short int也被轉換成int,否則它會被提升為unsigned int。
wchar_t和枚舉類型被提升為能夠表示其底層類型(underlying type)所有值的最小整數類型。
一旦整值提升執行完畢,類型比較就又一次開始。如果一個運算元是unsigned long型,則第二個也被轉換成unsigned long型。如果兩個運算元的類型都不是unsigned long,而其中一個運算元是long型,則另一個也被轉換成long型。long 類型的一般轉換有一個例外,如果一個運算元是long型,而另一個是unsigned int型,那麼只有機器上的long型足夠長,以便能夠存放unsigned int的所有值時(一般來說,在32位作業系統中,long型和int 型都用一個字長來表示,所以不滿足這裡的假設條件),unsigned int才會被轉換為long型,否則兩個運算元都被提升為unsigned long型。若兩個運算元都不是long型,而其中一個是unsigned int型,則另一個也被轉換成unsigned int 型。否則兩個運算元一定都是int 型。
int d = -1;
if (d <= sizeof(arr)/sizeof(arr[0]))
...
這樣的比較語句有問題,sizeof運算子返回無符號數。
if語句在signed int和unsigned int之間測試相等性,按照上面的說法,可以這樣解釋:
首先,signed int和unsigned int長度相同,不會向更長的方向轉換。
其次,signed int不能完整地表示unsigned int的所有值。
因此,signed int d被轉換為unsigned int類型。
這樣,-1就變成一個非常巨大的正整數,導致比較結果與預期的不符。
解決的方法是使用強制轉換,(int)(sizeof(arr)/sizeof(arr[0]))。
我在VC++ 6.0和DEV-C++ 4.9.9.0中嘗試了上面那段代碼,的確如此。
不要因為無符號數不存在負值而用它表示數量(如年齡、國債等),盡量使用int之類的有符號數,這樣在混合運算中,這樣就不必擔心邊界情況(如-1被翻譯為非常大的正數)。
只有在使用位段和二進位掩碼時,才使用無符號數。
應該在運算式中使用強制類型轉換,使所有的運算元均為有符號數或無符號數,這樣就不必由編譯器來選擇結果的類型。