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

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

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