偶然看到一道C++面試題:
void foo(void)

{
unsigned int a = 6;
int b = -20;
(a+b>6)?puts(">6"):puts("<=6");//puts為打印函數
}

問輸出是什么?答案是輸出 >6。
這道題主要考察兩個東西。
1.隱式類型轉換:int型變量轉化成unsigned int, b成了正數.
2.負數的補碼:計算機系統中的數值是以補碼形式表示(存儲)的。
一、C++隱式類型轉換
C++定義了一組內置的類型對象之間的標準轉換,在必要時它們被編譯器隱式的應用到對象上。在算式轉換保證了二元操作符,如加法或乘法的兩個操作數被提升為共同的類型,然后再用它表示結果的類型。兩個通用的指導原則如下:
1、為防止精度損失,如果必要的話,類型總是被提升為較寬的類型。
2、所有含有小于整形的有序類型的算術表達式在計算之前其類型都會被轉換成整形。
規則的定義如上面所述,這些規則定義了一個類型轉換層次結構,我們從最寬的類型long double 開始,那么另一個操作數無論是什么類型都將被轉換成long double .如果兩個操作數千不是long double 型,那么若其中一個操作數的類型是double 型,則另一個就被轉換成double 型。例如:
int ival;
float fval;
double dval;
dval + fval + ival //在計算加法前fval和ival都被轉換成double
類似地,如果兩個操作數都不是double型而其中一個操作float型 ,則另一個被轉換成float型。例如:
char cval;
int ival;
float fval;
cval + ival + fval //在計算加法前ival和cval都被轉換成float
否則如果兩個操作數都不是3種浮點類型之一,它們一定是某種整值類型。在確定共同的目標提升類型之前,編譯器將在所有小于int 的整值類型上施加一個被稱為整值提升的過程。
在進行整值提升時類型char、signed char、unsigned char和short int 都被提升為類型int 。如果機器上的類型空間足夠表示所有unsigned short 型的值,這通常發生在short用半個字而int 用一個字表示的情況下,則unsigned short int 也被轉換成int 否則它會被提升為unsigned int 。wchar_t和枚舉類型被提升為能夠表示其底層類型所有值的最小整數類型。在下列表達式中:
char cval;
bool found;
enum mumber{m1,m2,m3}mval;
unsigned long ulong;
cval + ulong;ulong + found; mval + ulong;
在確定兩個操作數被提升的公共類型之前,cval found 和mval都被提升為int 類型。
一旦整值提升執行完畢,類型比較就又一次開始。如果一個操作數是unsigned long 型,則第二個也被轉換成unsigned long 型。在上面的例子中所有被加到ulong上的3個對象都被提升為unsigned long 型。如果兩個操作數類型都不是unsigned long型 而其中一個操作數是long型,則另一個也被轉換成long型。例如:
char cval;
long lval;
cval + 1024 + lval; //在計算加法前cval和1024都被提升為long型。
long類型的一般轉換有一個例外。如果一個操作數是long型而另一個是unsigned int 型,那么只有機器上的long型的長度足以容納unsigned int 的所有值時(一般來說,在32位操作系統中long型和int 型都用一長表示,所以不滿足這里的假設條件),unsigned int 才會被轉換為long型,否則兩個操作數都被提升為unsigned long 型。若兩個操作數都不是long型而其中一個是unsigned int 型,則另一個也被轉換成unsigned int 型,否則兩個操作數一定都是int 型。
一般來說各種類型的長度關系為 long double > double > float >= int >= short > char,unsigned > signed 。
盡管算術轉換的這些規則帶給你的困惑可能多于啟發,但是一般的思想是盡可能地保留類型表達式中涉及到的值的精度。這下是通過把不同的類型提升到當前出現的最寬的類型實現的。
二、負數的補碼
在計算機系統中,數值一律用補碼來表示(存儲)。
主要原因:使用補碼,可以將符號位和其它位統一處理;同時,減法也可按加法來處理。另外,兩個用補碼表示的數相加時,如果最高位(符號位)有進位,則進位被舍棄。
補碼與原碼的轉換過程幾乎是相同的。
數值的補碼表示也分兩種情況:
(1)正數的補碼:與原碼相同。
例如,+9的補碼是00001001。
(2)負數的補碼:符號位為1,其余位為該數絕對值的原碼按位取反;然后整個數加1。
例如,-7的補碼:因為是負數,則符號位為“1”,整個為10000111;其余7位為-7的絕對值+7的原碼0000111按位取反為1111000;再加1,所以-7的補碼是11111001。
已知一個數的補碼,求原碼的操作分兩種情況:
(1)如果補碼的符號位為“0”,表示是一個正數,所以補碼就是該數的原碼。
(2)如果補碼的符號位為“1”,表示是一個負數,求原碼的操作可以是:符號位為1,其余各位取反,然后再整個數加1。
例如,已知一個補碼為11111001,則原碼是10000111(-7):因為符號位為“1”,表示是一個負數,所以該位不變,仍為“1”;其余7位1111001取反后為0000110;再加1,所以是10000111。