關於有符號數和無符號數的轉換 - C/C++


轉載自:http://www.94cto.com/index/Article/content/id/59973.html

1.引例:

今天在做了一道關於有符號數和無符號數相互轉換及其左移/右移的問題,被它們之間的轉換原理和位移原理搞得頭大了。真的很后悔本科的時候沒有認真學習《計算機組成原理》/《計算機操作系統》等計算機基礎課程。以下是我根據相關知識回顧和整理的材料,如有和某某的文章有雷同之處,請勿見怪。另外也希望看到這篇文章的同志們能夠有所收獲吧。

#include <cstdio> #include <iostream> using namespace std; int main() { unsigned short int ui; signed short int si; ui = (unsigned short int)0x8000u; si = (signed short int)0x8000; printf("ui = %u\n",ui); printf("si = %d\n",si); ui = ui>>1; si = si>>1; printf("ui = %u\n",ui); printf("si = %d\n",si); cout<<"------------------------------"<<endl; ui = (unsigned short int)0x8000u; si = (signed short int)0x8000; printf("%u\n",ui); printf("%d\n",si); ui = ((signed short int)ui>>1); si = ((unsigned short int)si>>1); printf("%u\n",ui); printf("%d\n",si); cout<<"------------------------------"<<endl; ui = (unsigned short int)0x8000u; si = (signed short int)0x8000; printf("%u\n",ui); printf("%d\n",si); ui = ui<<1; si = si<<1; printf("%u\n",ui); printf("%d\n",si); cout<<"-------------------------------"<<endl; ui = (unsigned short int)0x8000u; si = (signed short int)0x8000; printf("%u\n",ui); printf("%d\n",si); ui = ((signed short int)ui<<1); si =((unsigned short int)si<<1); printf("%u\n",ui); printf("%d\n",si); return 0; }

顯示結果:

ui = 32768
si = -32768
ui = 16384
si = -16384
------------------------------
32768
-32768
49152
16384
------------------------------
32768
-32768
0
0
-------------------------------
32768
-32768
0
0

2.概念
 在計算機中,可以區分正負類型的數,成為“有符號數”(signed);無正負類型的數(只有整數類型),成為“無符號數”(unsigned)。簡明的說,無符號說就是其所有的位數都用來表示數值的大小,有符號數除最高位來表示數值的正負外(0表示正數;1表示負數),其余各位用來表示數值的大小。舉個例子說明一下:十機制數 正數255  二進制表達形式:1111 1111

十機制數 負數-1     二進制表達形式:1111 1111 

可見-1的二進制的最高位為紅色的1,可是為什么其表達形式為1111 1111而不是1000 0001呢?這就關於任何數在計算機內是以補碼形式存儲問題。下面會介紹的,在此先不詳細說明了。

3.存儲范圍

從前面的介紹可以知道,由於有符號數的最高位被拿來用作符號位,所以它所能夠表達的最大數值要小於無符號數所能夠表達的最大數值。還是舉個例子來說明一下吧:

無符號數:1111 1111 十進制值:255

有符號數:0111 1111 十進制值:127

這是有人可能會提出這樣的疑問:有符號數所能夠表達的數值范圍會不會小於無符號數所能夠表達的數值范圍呢?

呵呵,答案是否定的!雖然有符號數在表達最大值上的能力減弱了,但是它能夠表達負數。負數的個數可以彌補其不足。來讓我們比較一下:

一個字節的無符號數的表達數值范圍是:[0,255]

一個字節的有符號數的表達數值范圍是:[-128,0),[0,127]

可見它們都能夠表示256個數。

4.各種碼(原碼/反碼/補碼)

有些人也許會這樣認為"-1"(雙字節)在計算機中的表達形式為1000 0000 0000 0001,可是實際上不是的。計算機是以其補碼的形式進行表達的,即“-1”(雙字節)的表達形式是1111 1111 1111 1111。

說一下各種碼的概念吧。

原碼:一個整數,按照絕對值的大小轉換成二進制數,最高位為符號位。

反碼:將原碼除最高位(符號位)外,其余各位按位取反,所得到的二進制碼。正數的反碼為原碼。

補碼:反碼最低位加1即為補碼。

關於負數的補碼求法說明一下,先得到其反碼,之后將反碼加1即可。有些大神根據其原碼,閉眼即得,這種能力需要修煉一下啊。

這時有些人可能會說,為什么要引入補碼的形式呢?直接按照原碼存儲不就省事很多嗎?嘿嘿,要記住,有些事情並不是你想省事就能省事的。好了來欣賞一下補碼的優勢吧。

計算機的帶符號數用補碼表示的優點:

1負數的補碼與對應正數的補碼之間的轉換可以用同一種方法-求補運算完成,可以簡化硬件。 2 可將減法變為加法,這樣減法就可以用加法器進行計算了。 3 兩個用補碼表示的數相加時,如果最高位(符號位)有進位,則進位被舍棄。

心算求補(大神求補算法):

從最低位開始至找到的第一個1均不變,符號位不變,這之間的各位“求反”(0變1;1變0)。

原碼:1010 1001  補碼:1101 0111.

5.有符號數與無符號數的相互轉換

無符號整數和有符號整數之間進行強制類型轉換時,位模式不改變。

有符號數轉換為無符號數時,負數轉換為大的正數,相當於在原值上加上2的n次方,而正數保持不變。

無符號數轉換為有符號數時,對於小的數將保持原值,對於大的數將轉換為負數,相當於原值減去2的n次方。

當表達式中存在有符號數和無符號數類型時,所有的操作都自動轉換為無符號類型。可見無符號數的運算優先級高於有符號數。

unsigned int a = 20; signed int b = -130;

 運算一下結果是 b>a 。

6.轉換大餐

有符號數的轉換

原類型 目標類型 轉換方法
 char

short

符號位擴展
char long 符號位擴展
char unsigned char 最高符號位失去位意義,變為數據位
char unsigned short 符號位擴展到short;然后從short轉到unsigned short
char unsigned long 符號位擴展到long;然后從long轉換到unsigned long
char float 符號位擴展到long;然后從long轉到float
char double 符號位擴展到long;然后從long轉換到double
char long double 符號位擴展到long;然后從long轉換到long double
short char 保留低位字節
short long 符號位擴展
short unsigned char 保留低位字節
short unsigned short

最高為失去意義,變為數據位

short unsigned long 符號位擴展到long;然后從long轉到unsigned long
short float 符號位擴展到long;然后從long轉到float
short double 符號位擴展到long;然后從long轉到double
short long double 符號位擴展到long;然后從long轉換到long double
long char 保留低位字節
long short 保留低位字節
long unsigned char 保留低位字節
long unsigned short 保留低位字節
long unsigned long 最高為失去意義,變為數據位
long float 使用單精度浮點數表示,可能失去精度
long double 使用單精度浮點數表示,可能失去精度
long long double 使用單精度浮點數表示,可能失去精度

無符號數的轉換

原類型 目標類型 轉換方法
unsigned char char 最高為作符號位
unsigned char short 0擴展
unsigned char long 0擴展
unsigned char unsigned short 0擴展
unsigned char unsigned long 0擴展
unsigned char float 轉換到long;然后從long轉換到float
unsigned char double 轉換到long;然后從long轉換到double
unsigned char long double 轉換到long;然后從long轉換到long double
unsigned short char 保留低位字節
unsigned short short 最高為作符號位
unsigned short long 0擴展
unsigned short unsigned char 保留低位字節
unsigned short unsigned long 0擴展
unsigned short float 轉換到long;然后從long轉換到float
unsigned short double 轉換到long;然后從long轉換到double
unsigned long long double 轉換到long;然后從long轉換到long double
unsigned long char 保留低位字節
unsigned long short 保留低位字節
unsigned long long 最高位作符號位
unsigned long unsigned char 保留低位字節
unsigned long unsigned short 保留低位字節
unsigned long float 轉換到long;然后從long轉換到float
unsigned long double 直接轉換到double
unsigned long long double 轉換到long;然后從long轉換到long double

7.各種數據類型所占字節

32位平台下:


免責聲明!

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



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