標籤:電腦 電腦科學
C語言的有符號與無符號,二進位整數的擴充與截斷
前一節說了整數的表示方式,,也就是無符號編碼與補碼編碼.這一屆說一下二進位整數的擴充與截斷,這部分內容與C語言掛鈎.so,我們先看以下C語言的有符號和無符號數.
C語言中的有符號數和無符號數
有符號數和無符號數的本質區別其實就是採用的編碼不同,前者採用補碼編碼,後者採用無符號編碼.
在C語言中,有符號數和無符號數是可以隱式轉換的,不需要手動實施強制類型轉換.不過也正是因為如此,可能你一不小心就將一個無符號數賦給了有符號數.就會造成出乎意料的結果,就像下面這樣:
#include <stdio.h>
int main(){
short i = -12345;
unsigned short u = i;
printf("%d %d\n",i,u);
}
你自己觀察一下輸出結果你就會發現,一個負數變成了正數,再看下面這個程式,他展示了在進行關係運算時,由於有符號數和無符號數的隱式轉換所導致的違背常規的結果.
#include <stdio.h>
void main(){
printf("%d\n",-1 < 0U);
printf("%d\n",-12345 < 12345U);
}
你自己看看輸出結果,兩個結果都是0,也就是false,這與我們直觀的理解是違背的,原因就是因為在比較的過程中,有符號數被隱式的轉換成了無符號數進行比較.
擴充
當我們將一個短整型的變數轉換為整型變數時,就涉及到了位的擴充,此時由兩個位元組擴充為四個位元組.
在進行位的擴充時,最容易想到的就是在高位全部補0,也就是將原來的二進位序列前面加入若干個0,也稱為零擴充.還有一種方式比較特別,是符號擴充,也就是針對有符號數的方式,他是直接擴充符號位,也就是將二進位序列的前面加入若干個最高位.
對於零擴充來說,很明顯擴充之後的值與原來的值是相等的,而對於符號擴充來說,則是一樣,只不過沒有零擴充來的直觀.我們在計算補碼時有一個比較簡單的辦法,就是符號位若為0,則與無符號是類似的.若符號位為1,也就是負數時,可以將其餘位取反最終再加1即可.因此當我們對一個有符號的負數進行符號擴充時,前面加入若干個1,在取反之後都為0,因此依舊會保持原有的數值.
總之,在對位進行擴充式,是不會改變原有數值的.
在書中對於負數的符號擴充還給出了這一過程的證明,其實這個證明很簡單,就是利用了補碼編碼的公式而已.需要多提一點的是,這是使用了歸納法證明,因此這裡只是擴充了以為,具體過程如下:
截斷
截斷與擴充相反,它是將一個多維二進位序列截斷為較少的位元,就是與擴充是相反的過程.
根據我們的直觀判斷也不難發現,截斷可能會導致資料的丟失.對於無符號編碼來說,截斷後就是剩餘位元的無符號編碼數值.在書中給出了這一簡單過程證明,它主要是想表明截斷前後的數值的關係是模數所得到的.
對與補碼編碼來說,截斷後的二進位序列與無符號編碼是一樣的,因此我們只需要多加一步,將無符號編碼轉換為補碼編碼就好了.因此對於無符號編碼和補碼來說,可以得到以下兩個公式.
其他語言中的有符號和無符號
從上面的分析可以看出,具有有符號和無符號的語言,可能引起一些不必要的麻煩,而且無符號數除了能表示的最大值更大以外,似乎沒什麼好處了.因此有很多語言是不支援無符號數的.
我接觸過的C#和JAVA就只有有符號數,這樣省去了很多不必要的麻煩.無符號數很多時候只是為了表示一些無數值意義的標識,比如我們的記憶體位址,此時的無符號數有點類似資料庫主鍵或者說鍵值對中的鍵值的概念,僅僅是一個標識而已.
小結
低位轉高位叫擴充,高位轉低位叫做截斷.
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
C語言的有符號與無符號,二進位整數的擴充與截斷