算術轉化和整型提升的奧祕
首先請大家先思考一下3個問題,問題相互之間是有關聯的。
1,整型字面值是屬於整型家族9種中的哪一種呢?
2,什麼是算術轉換?如何轉換的?
3,什麼是整型提升?如何提升的?為什麼會有整形提升?
下面解答上述問題。
1,整型字面值是屬於整型家族9種中的哪一種呢?
答案取決於字面值時如何書寫的。比如在整數字面值後面後面新增字元L或l,可以使這個整數被解釋為long整型值,字元U或u則用於把數值制定為unsigned整型值。如果在一個字面值後面各新增這兩組字元中的一個,那麼它就解釋為unsigned long整型值。
整型字面值可能int,long或unsigned long。在預設情況下,它是最短型別但能完整容納這個值。
例如:在監視中,我們可以明確的看到編譯器對於整型字面值在計算時是如何儲存的
可以看出即便是再小的數,也會當做是int型,隨著整數的增大,整數的型別也會隨著變大。直到超出最大範圍。
2,什麼是算術轉換?如何轉換的?
算術轉化:如果某個操作符的各個運算元屬於不通過的型別,那麼除非其中一個運算元轉換為另外一個運算元的型別,否則操作就無法進行。
下面的層次體系稱為尋常算術轉換(usual arithmetic conversion)
long double
double
float
unsigned long int
unsigned int
int
vs文件中常用算術轉換規定。
-
如果任一運算元是 long double
-
如果未滿足上述條件,並且任一運算元是 double 型別,則將另一個運算元轉換為 double 型別。
-
如果未滿足上述兩個條件,並且任一運算元是 float 型別,則將另一個運算元轉換為 float 型別。
-
如果未滿足上述三個條件(所有運算元都不是浮點型),則對運算元執行整型轉換,如下所示:
-
如果任一運算元是 unsigned long 型別,則將另一個運算元轉換為 unsigned long 型別。
-
如果未滿足上述條件,並且任一運算元是 long 型別且另一個運算元是 unsigned int 型別,則將兩個運算元都轉換為 unsigned long
-
如果未滿足上述兩個條件,並且任一運算元是 long型別,則將另一個運算元轉換為 long 型別。
-
如果未滿足上述三個條件,並且任一運算元是 unsigned int型別,則將另一個運算元轉換為 unsigned int 型別。
-
如果未滿足上述任何條件,則將兩個運算元轉換為 int 型別。
-
例子:
int a = -1;
unsigned int b = 0xffffffff;
char c = -1;
if (a > b)
printf("a > b\n");
else if (a == b)
printf("a = b\n");
else
printf("a < b\n");
if (c > sizeof(c))
printf("c > sizeof(c)\n");
輸出:
解析:
結果並沒有按照我們想的大小來比較,而是發生了我們沒有看見的隱式算術轉換。
int型別a和unsigned int型別b來運算元'<'、'=='、'>'兩邊,比較時,其中a發生算術轉換暫時變為unsigned int a.而-1的補碼和0xffffffff的補碼相同,所以兩數相同。輸出a = b;
同理。sizeof()返回值為size_t型別的1, unsigned int。char c會變為unsigned int c,然後與unsigned int 1比較大小,自然是大於1.
3,什麼是整型提升?為什麼會有整形提升?如何提升的?
概念:C的整型算術運算總是至少以預設整數型別的精度(int)來進行的。為了獲取這個精度,表示式中的字元型和短整型運算元在使用之前被轉化為普通整型,這種轉化稱為整型提升(integral Promotion)。換句話說,在表示式計算時,各種整型首先要提升為int型別,如果int型別不足以表示則要提升為unsigned int型別,然後進行表示式的運算。
存在原因:通常情況下,在32位平臺下,在對int型別的數值做運算時,CPU的運算速度是最快的。C語言是一個注重效率的語言,所以它會做整型提升,使得程式執行速度更快。
提升規則:有符號的在左邊補上符號位,無符號的在左邊補上0。
想要知道有沒有整型提升,關鍵還是要看彙編。
例子:
注意下圖中的彙編語句,對比char和int的不同
可以發現,在初始化a,b,aa,bb時,都是用整型字面值賦值。對於a,b來說只是截取了其中一部分。但不影響獲得後a,b的內容。
重點:對比 char c = a+b;和int cc = aa+bb;這兩行程式碼的彙編不同;
一個是movsx,一個是mov;
movsx:表示帶符號擴充套件,並傳送。
即:在計算c時,a和b進行了符號擴充套件,b和c的值被提升為普通整型,然後再執行加法運算。加法運算的結果將被截斷,然後在儲存於c中。
下面給出一個整型提升方面的經典例子。
char c;
unsigned char uc;
unsigned short us;
c = 128;
uc = 128;
us = c + uc;
printf("Ox%x\n", us);
us = (unsigned char)c + uc;
printf("0x%x\n", us);
us = c + (char)uc;
printf("0x%x\n", us);
各位可以試著練練手,畫畫圖。然後與答案對比下。
答案:
注意有無符號數字的儲存形式。
如何整型提升的
注:算術變換和整形提升的區別:
算術變換主要針對操作符兩邊運算元型別不同,用來解決型別不匹配問題。
整型提升主要針對運算元是否便於計算,用來解決計算求值問題。