使用無符號類型要特別注意

一個由無符號類型引發(fā)的微妙的錯誤

#include <stdio.h>  
#include  <string.h>

int main()
{
    char array[] = "hello";
    int d = -1, x;
    //(1)//if (d <= sizeof(array) / sizeof(char))    
    //(2)//if (d <= strlen(array))

    //if (d <= (int)sizeof(array) / sizeof(char))    /*輸出:x = 104*/     
    if (d <= (int)strlen(array))        /*輸出:x = 104*/
    {
        x = array[d + 1];
        printf("x = %d\n", x);  //字符'h'對應(yīng)的ASCII碼是104,   'a'是97
    }
    else
    {
        printf("sizeof(array) / sizeof(char) = %u\n", sizeof(array) / sizeof(char));
        printf("strlen(array) = %u\n", strlen(array));  
      //用%d輸出也是一樣,都是正數(shù)
    }

    return 0;
}
  • 這個程序若用(1)或(2)的判斷條件會輸出:
    sizeof(array) / sizeof(char) = 6
    strlen(array) = 5
    加上強制類型轉(zhuǎn)換(int)才會輸出:x = 104

(1)原因是sizeof操作符(注意它不是一個函數(shù),也可以有 sizeof char;sizeof(char);效果一樣)的返回值類型是size_t,而typedef unsigned int size_t;
所以在執(zhí)行表達式d <= sizeof(array)/sizeof(char)時,右邊表達式結(jié)果為無符號整型6,因此會將左邊的整型d裝換成無符號整型(-1(在計算機中以1的補碼形式存在為二進制1111...11111)將變成變成一個超級大的整數(shù)),因此判斷結(jié)果是false。

改正方法:d <= (int)sizeof(array)/sizeof(char),人為增加強制類型轉(zhuǎn)換,這樣就不必由編譯器來選擇結(jié)果的類型了。

(2)同理,strlen()函數(shù)的返回值類型也是size_t,而typedef unsigned int size_t;。但是注意strlen()函數(shù)和sizeof操作符的區(qū)別,sizeof會多計算一個結(jié)束符'\0'的大小,因此會多1,而strlen()函數(shù)總是只計算實際字符串字符個數(shù)。

改正方法:d <= (int)strlen(array),人為增加強制類型轉(zhuǎn)換,這樣就不必由編譯器來選擇結(jié)果的類型了。

對無符號類型的建議(《C專家編程》第24頁)

1、盡量不要在代碼中使用無符號類型,以免增加不必要的麻煩,尤其是,不要僅僅因為無符號類型不存在負值(如年齡)而用它來表示數(shù)量,可以多增加if-else判斷數(shù)量的合法性也比用無符號類型更安全。否則一個int的 -1,由編譯器自動升級成無符號型int,將會變成一個非常大的數(shù)。
2、如果用了,應(yīng)該在表達式中使用強制類型轉(zhuǎn)換,使操作數(shù)均為有符號或者無符號類型,這樣就不必由編譯器來選擇結(jié)果的類型,可以避免微妙的錯誤發(fā)生。
3、只有在使用位段和二進制掩碼時,最好去用無符號數(shù)。這里就要談到正數(shù)和負數(shù)在計算機中的二進制存儲方式了。正數(shù)簡單,就是原碼二進制形式存儲,如int型32bit位 int a = 1;那么a在計算機中存儲為二進制000...(總共31個0)...0001。但是負數(shù)就比較復(fù)雜,要用原碼求反碼再加1得到的補碼的二進制形式存儲在計算機中,如int b = -1;原碼和a一樣,反碼就是111...(總共31個1)...1110,然后反碼加1得到補碼111...(總共32個1)...1111??梢奲并不是簡單的存儲為二進制100...(總共30個0)...0001。因此在使用位段和二進制掩碼這些需要按bit位操作的情況下,為了在使用時讓我們腦子里想的和計算機處理的一致,盡量都用無符號類型,就可以避免負數(shù)在計算機中的特殊存儲方式帶來的影響。
《注意:負數(shù)要以10進制輸出時,又要將計算機中存儲的補碼,先減1求得反碼,再按位求反得到原碼,然后將原碼轉(zhuǎn)換成10進制輸出并在前面添加一個‘-’號》

使用無符號類型的優(yōu)缺點

  • 比如int類型和unsigned int類型,同樣是占用4字節(jié)(32bit位),int類型的取值范圍是(-2^31到2^31),而unsigned int類型的取值范圍是(0到2^32),可見在利用正數(shù)的這一半時無符號數(shù)的可用范圍是有符號的兩倍。有符號數(shù)最高bit位的0或1只能表示+-符號,不能表示數(shù)值,浪費了。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容