C語言有符號與符號引數的比較
1.整型無符號引數與有符號引數比較
程式碼段:
#include<cstdio>
int main()
{
int a=-1;
unsigned int b=0;
if(b>a)printf("b>a\n");
else printf("b<a\n");
printf("a int unsigned:%u\na in int:%d",a,a);
getchar();
}
執行結果:
b<a
a int unsigned: 4294967295
a in int: -1
原因:計算機中整數以補碼的形式儲存的【正數的補碼等於原碼;負數的補碼等於反碼加1,而反碼等於原碼符號位不變,其餘各位取反
-1 = 1000 0000 0000 0000 0000 0000 0000 0001 原碼
-1 = 1111 1111 1111 1111 1111 1111 1111 1110 反碼
-1 = 1111 1111 1111 1111 1111 1111 1111 1111 補碼
解決方案:if(b>(int)a)
正數無符號轉換成有符號型別沒有問題,只是將最高位當做符號位(正數0,負數1)
2.整型無符號與有符號減法
錯誤程式碼:
float sum_elements(float a[], unsigned length)
{
int i = 0;
float sum = 0;
for(i = 0; i <= length -1; ++i)
{
sum += a[i];
}
return sum;
}
如果我告訴你這是一段有錯的程式碼,可能你也不太相信,因為這個函式的一切看起來是這麼的自然,因為資料的長度(或個數)肯定是一個非負數,所以把length宣告為一個unsigned很合理,計算的資料個數和返回型別也正確。的確如此,但是這都是在length不為0的情況,試想,當呼叫函式時,把0作為引數傳遞給length會發生什麼事情?回想一下前面我們所說的知識,因為length是unsigned型別,所以所有的運算都被隱式地被強制轉換為unsigned型別
解決方案:for(i = 0; i < length; ++i)
3. strlen比較
錯誤程式碼:
int strlonger(char *s1, char *s2)
{
return strlen(s1) - strlen(s2) > 0;
}
size_t strlen(const char *s);
注意這裡有一個數據型別size_t,它被定義在stdio.h檔案中,其實它就是unsigned int,一個字串的長度當然不可能為負,這樣的定義顯然是合理的,但是有時卻因為這樣,而存在不少的問題,如函式strlonger的實現。當s1的長度大於等於s2時,這個函式並沒有什麼問題,但是你可以想像,當s1的長度小於s2的長度時,這個函式會返回什麼嗎?沒錯,因為此時strlen(s1) - strlen(s2)為負(從數學的角度來解釋的話),而又由於程式把它作為unsigned為處理,則此時的值肯定是一個比0大的值。換句話來說,這個函式只有在strlen(s1) == strlen(s2)時返回假,其他情況都返回真。
解決方案:
從執行結果來看,確實如此,只要s1與s2長度不等,就返回真。那麼我們在怎麼樣改善這段程式碼呢?其實答案也是很簡單的,所函式改為如下即可:
修改之後:
int strlonger(char *s1, char *s2)
{
return strlen(s1) > strlen(s2);
}
這樣就可以利用兩個無符號數進行直接的比較,而不會因為減法而出現負數(數學上來說)而影響比較結果。