Integer Promotions in C 簡介
整型提升是C程序設計語言中的一項規(guī)定:在表達式計算時,各種整形首先要提升為int類型,如果int類型不足以表示的話,就需要提升為unsigned int類型,然后再執(zhí)行表達式的運算。
這一規(guī)則是由C語言的發(fā)明人丹尼斯·里奇與肯·湯普遜創(chuàng)設的:
"A character, a short integer, or an integer bit-field, all either signed or not, or an object of enumeration type, may be used in an expression wherever an integer maybe used. If an int can represent all the values of the original type, then the value is converted to int; otherwise the value is converted to unsigned int. This process is called integral promotion."
這段話的大意是:無論使用什么整數(shù),都可以在表達式中使用char,short int或 int字段(全部帶符號或沒有符號)或枚舉類型的對象。如果一個int可以代表原始類型的所有值,則該值將轉(zhuǎn)換為int;否則,該值將轉(zhuǎn)換為unsigned int,這個過程稱為整體提升。
舉例子來了解一下整形提升
一些數(shù)據(jù)類型(比如char,short int)比int占用更少的字節(jié)數(shù),對它們執(zhí)行操作時,這些數(shù)據(jù)類型會自動提升為int或unsigned int,例如,在較小的類型(如char,short和enum)上不會進行算術計算,代碼如下:
1//在win10_64位+vs2017 2#include 3int main() 4{ 5 char a = 30, b = 40, c = 10; 6 char d = (a * b) / c; 7 printf ("%d ", d); 8 system("pause"); 9 return 0; 10}
輸出結果:120
直接看代碼,表達式(a * b)/ c似乎引起算術溢出,因為帶符號的字符只能具有-128至127的值(在大多數(shù)C編譯器中),而子表達式的值(a * b)=1200,大于128。
但是整數(shù)提升是在char類型進行算術運算時發(fā)生的,我們得到了適當?shù)慕Y果而沒有任何溢出。
整型提升的意義
雖然機器指令中可能有現(xiàn)兩個8比特字節(jié)這種字節(jié)相加指令,但是一般用途的CPU是難以直接實現(xiàn)這樣的字節(jié)相加運算的。
所以,表達式中各種長度可能小于int長度的整型值,都必須先轉(zhuǎn)換為int或unsigned int,然后才能送入CPU去執(zhí)行運算。
CPU內(nèi)整型運算器(ALU)的操作數(shù)的字節(jié)長度一般就是int的字節(jié)長度,同時也是CPU的通用寄存器的長度。而表達式的整型運算要在CPU的相應運算器件內(nèi)執(zhí)行。
因此,兩個char類型的樹進行相加運算時,是在CPU中執(zhí)行,自然而然的需要先轉(zhuǎn)換為CPU內(nèi)整型操作數(shù)的標準長度。
應用舉例
short int的長度 = int的長度的情況
C語言標準中僅規(guī)定了:
char的長度 ≤ short int的長度 ≤ int的長度
這意味著short int與int的長度相等的可能,這種情形下,unsigned short就無法提升為int表示,只能提升為unsigned int,代碼如下:
1//在win10_64位+vs2017 2#include 3int main(){ 4 char a = 0xb6; 5 short b = 0xb600; 6 int c = 0xb6000000; 7 if ( a == 0xb6) printf("a"); 8 if ( b == 0xb600) printf("b"); 9 if ( c == 0xb6000000) printf("c"); 10 system("pause"); 11}
輸出結果:c
C語言標準沒有規(guī)定char類型是有符號還是無符號,在這些環(huán)境下,編譯器把char定義為signed char。
表達式a==0xb6被整型提升,其中char類型的a提升為int類型并表示為一個負值,因此這個表達式的結果為false;
表達式b==0xb600被整型提升,其中short類型的b提升為int類型并為一個負值,因此這個表達式的結果為false;
表達式c == 0xb6000000沒有做整型提升,==運算符的兩段都是int類型的負值,其結果為true。
我們再考慮以下程序作為另一個示例。
1//在win10_64位+vs2017 2#include 3 4int main() 5{ 6 char a = 0xfb; 7 unsigned char b = 0xfb; 8 9 printf("a = %c", a); 10 printf("\nb = %c", b); 11 12 if (a == b) 13 printf("\nSame"); 14 else 15 printf("\nNot Same"); 16 17 system("pause"); 18 return 0; 19}
輸出結果:
a=
b=
Not Same
當我們打印“a”和“b”時,將打印相同的字符,但是當我們比較它們時,輸出的結果卻不相同。
“a”和“b”與char具有相同的二進制表示形式,但是,當對“a”和 ”b”執(zhí)行比較操作時,它們首先會轉(zhuǎn)換為int。
“a”是一個有符號的字符,當轉(zhuǎn)換為int時,其值變?yōu)?5(有符號的值0xfb)。
“b”是無符號字符,當將其轉(zhuǎn)換為int時,其值變?yōu)?51。
值-5和251具有不同的int表示形式,因此我們得到的輸出為“Not Same”。
前綴+的情況
C語言的單操作數(shù)的+運算符(即“前綴+”),一個主要作用就是實現(xiàn)對操作數(shù)的整型提升。例如:
1//在win10_64位+vs2017 2#include 3int main() 4{ 5 char a = 1; 6 printf("%u", sizeof(a) ); 7 printf("\n"); 8 printf("%u", sizeof( +a ) ); 9 system("pause"); 10 return 0; 11}
輸出結果:
1
4
從結果中我們可以看到,前綴+把大小給提升了。
話說C語言的特點
這里不得不提一下C語言的特點,C語言高效、靈活、功能豐富、表達力強,在誕生起初,為了避免各開發(fā)廠商用的C語言語法產(chǎn)生差異,C語言訂定了一套語法ANSI C,作為C語言的標準。
以上所有的程序以及結論都是在win10_64位+vs2017完成的,不同平臺和不同編譯器之間可能的實驗結果都不一樣,但這并不影響我們深入理解C語言的特性,講原理,摳細節(jié),究根源,樂趣在此。
免責聲明:本文內(nèi)容由21ic獲得授權后發(fā)布,版權歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!