如何用一個語句判斷一個整數是不是二的整數次冪——從一道簡單的面試題淺談C語言的類型提升(type promotion)


   最近招聘季,看JULY大哥的面試100題時,碰到這么一個擴展問題:

如何用一個語句判斷一個整數是不是二的整數次冪?(此題在編程之美也有)

  easy, 2的整數次冪的二進制形式只有一個1,只要用i和i-1按位相與,結果為零就說明是:

int i;

bool b = (i&(i-1))?false:true;

(===============只想知道這道題的解法的看到這里就夠了,以下都是無關內容===============)

 

   再下一步之前,請思考一個問題:printf("%d", sizeof('a');的輸出是什么?測試驗證你的想法后,帶着疑問向下看吧。

 

  為了簡單驗證算法的正確性,我寫了如下代碼:

typedef short bool

int main()
{
    char c = 1;
    int i = 1;

    while(i<9)
    {
        bool b = c&c-1;
        printf("%d : c = %d , b = %d\n",  i, c, b);

        i++;
        c<<=1;
    }
    return 0;
}

 

  輸出

1: c = 1 , b = 0
2: c = 2 , b = 0
3: c = 4 , b = 0
4: c = 8 , b = 0
5: c = 16 , b = 0
6: c = 32 , b = 0
7: c = 64 , b = 0
8: c = -128 , b = -256
//博客機跟開發機不是一台,還不能互聯, 純手打;

  

  好像有什么奇怪的東西混進來了,當1在第8位上的時候, c與c-1按位相與的值變成了-256,簡單思考知道這里發生了類型提升:

c = 0x80 = 1000 0000b = -128;

c - 1 提升至 int 型,變為 -129 = (int)0x ff ff ff 7f = (0x ff ff ff)0111 1111b

所以 c&(c-1)的結果為(short)0x ff ff ff 00 = -256

而(char)(c-1) = (char)0xff ff ff 7f = 0111 1111b = 127, 其二進制表示正好與c的互補。

  於是可以將代碼修改一下:

bool b = c&(char)(c-1); 

  

  由此得出了正確的結果。遺留兩個問題:

1.對於int型的值是否也會出現同樣問題呢?

2.C語言的類型提升發生在什么時候?

 

  對於問題1,答案是否定的,這一點可以通過簡單試驗得知,原理參見問題2的研究:

int apple = 1;
apple <<= 31;
int pear = apple & apple-1;

  

  首先,printf("%d", sizeof('a');的輸出是什么?(摘自C專家編程)

答案不是1,而是4(你編譯器里int的長度),原因是這里發生了類型提升。

The C Programming Language里的五句真言:

  如果沒有無符號的操作數,則有:

  1. 若存在long double的操作數, 則將其他操作數提升為long double。

  2. 否則,若存在double的操作數, 則將其他提升為double。

  3. 否則, 若存在float, 則提升為float。

  4. 否則, 將char和short提升為int。

  5. 然后, 若有long的操作數, 則將其他提升為long。

原文如下:

  If there are no unsigned operands, however, the following informal set of ules will suffice:

  1. If either operand is long double, convert the other to long double.

  2. Otherwise, if either operand is double, convert the other to double.

  3. Otherwise, if either operand is float, convert the other to float.

  4. Otherwise, convert char and short to int.

  5. Then, if either operand is long, convert the other to long.

  而對於unsigned操作數的情況下,則較為復雜,大致上記住無符號與有符號共存時,會向無符號提升。簡單建議不要有符號無符號混用。

詳細轉換規則請參見The C Programming Language;而有符號無符號混用編程可能導致的問題,請參見深入理解計算機系統(廣受好評的:CSAPP)。

  

  事實上,有了上面的五句真言,我們就可以了解答之前的問題了:

1.printf("%d", sizeof('a'); //在表達式中,每個char都被轉換為int,所以sizeof表達式計算的是:sizeof((int)'a'),其答案為4也就不足為奇;

2.對於文首提出的面試題,int型的值是否也會出現同樣問題呢?//答案是不會,因為表達式c&(c-1)中不存在類型提升;

3.C語言的類型提升發生在什么時候?//發生在類型混用的時候,存在char的表達式中一定存在類型轉換

 

 

=========================引用===========根據引用順序=========================

JULY的面試100題(感謝JULY大哥的無私奉獻精神):http://blog.csdn.net/v_july_v/article/details/6870251

C專家編程:http://book.douban.com/subject/2377310/

The C Programming Language:http://book.douban.com/subject/1139336/

Computer Systems : A Programmer's Perspective (second edition)(別猶豫,快去買一本): http://book.douban.com/subject/5333562/

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM