程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> ANSI C中的整型升級

ANSI C中的整型升級

編輯:關於C語言

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被翻譯為非常大的正數)。

只有在使用位段和二進制掩碼時,才使用無符號數。

應該在表達式中使用強制類型轉換,使所有的操作數均為有符號數或無符號數,這樣就不必由編譯器來選擇結果的類型。

C語言中的類型轉換比一般人想象中的要廣泛得多。

在涉及類型小於int或double的表達式中,都有可能出現類型轉換。

printf(" %d ", sizeof 'A');

的結果是4, 是int的長度,編譯器首先將'A'升級為整數97,再調用sizeof。

整型提升就是char、short int和位段類型(無論signed或unsigned)以及枚舉類型將被提升為int,前提是int 能夠完整地容納原先的數據,否則將被轉換為unsigned int。

ANSI C表示,如果編譯器能夠保證運算結果一致,也可以省略類型提升——這通常出現在表達式中存在常量操作數的時候。

另一個會發生隱式類型轉換的地方就是參數傳遞。

在K&R C中,由於函數的參數也是表達式,所以也會發生類型提升。

在ANSI C中,如果使用了適當的函數原型,類型提升便不會發生,否則也會發生。

在被調用函數的內部,提升後的參數被裁減為原先聲明的大小。

這就是為什麼單個的printf()格式字符串%d能適用於幾個不同類型,

short、char或int,而不論實際傳遞的是上述類型的哪一個。

函數從堆棧中(或寄存器中)取出的參數總是int類,並在printf或其他被調用函數裡按統一的格式處理。

printf是一個可變參數函數,此時一般的參數提升始終會發生。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved