有、無符號數之間的運算
有符號數與無符號數之間的運算,編譯器會進行隱式類型轉換。
請看如下代碼:
#include <stdio.h> int main(void) { unsigned int a = 6; int b = -20; if ( a+b > 6 ) printf("a+b大於6\n"); else printf("a+b小於6\n"); return 0; }
程序輸出結果為:
a+b大於6
原因是因為編譯器會將有符號數b轉換成為一個無符號數,即此處a+b
等價於a+(unsigned int)b
。
該程序運行在32bit環境下,b的值為0xFFFFFFFF-20+1 = 4294967276
,即a+b將遠遠大於6。
C 語言按照一定的規則來進行此類運算的轉換,這種規則稱為正常算術轉換
,轉換的順序為:
double>float>unsigned long>long>unsigned int>int
即操作數類型排在后面的與操作數類型排在前面的進行運算時,排在后面的類型將隱式轉換為排在前面的類型。
有、無符號數轉化為更大類型
請看如下代碼:
#include <stdio.h> int main(void) { //情況一 signed char c1 = 0xff; unsigned char c2 = 0xff; int a1,a2; a1 = (int)c1; a2 = (int)c2; printf("a1=%d(%#.8X),a2=%d(%#.8X)\n",a1,a1,a2,a2); //情況二 signed char c3 = 0x80; unsigned char c4 = 0x80; int a3,a4; a3 = (int)c3; a4 = (int)c4; printf("a3=%d(%#.8X),a4=%d(%#.8X)\n",a3,a3,a4,a4); //情況三 signed char c5 = 0x7f; unsigned char c6 = 0x7f; int a5,a6; a5 = (int)c5; a6 = (int)c6; printf("a5=%d(%#.8X),a6=%d(%#.8X)\n",a5,a5,a6,a6); return 0; }
程序輸出結果為:
a1=-1(0XFFFFFFFF),a2=255(0X000000FF) a3=-128(0XFFFFFF80),a4=128(0X00000080) a5=127(0X0000007F),a6=127(0X0000007F)
可見:
(1)將無符號數轉換為更大的數據類型時, 只需簡單地在開頭添加0至所需位數,這種運算稱為0擴展。
(2)將有符號數轉換為更大的數據類型需要執行符號擴展,規則是將符號位擴展至所需的位數,即符號位為0時在開頭添加0至所需位數,符號位為1時在開頭添加1至所需位數。
此外,還需注意,對於一個signed char類型數據,0xff代表的是-1,因為整數在內存中是以補碼的形式存儲的。
正數的原碼、反碼、補碼都相等。負數的反碼是將原碼中除符號位以外的所有位(數值位)取反,也就是 0 變成 1,1 變成 0;負數的補碼是其反碼加 1。
此處,對於一個signed char類型數據,-1的原碼為1000 0001,反碼為1111 1110,所以補碼為1111 1111。
signed char的負數對應表為(圖片來源於網絡):

其中,-128最為特殊,需要特別記住,其不遵循傳統的由補碼計算原碼的方法。
以上就是關於有符號數與無符號數的兩點總結:(1)有符號數與無符號數之間的運算,編譯器會進行隱式類型轉換。(2)有符號數、無符號數轉換為更大的數據類型。
本文參與騰訊雲自媒體分享計划,歡迎正在閱讀的你也加入,一