C中的有符號數和無符號數之間的轉換

2021-07-27 00:17:54 字數 3691 閱讀 3840

例:

[cpp]view plain

copy

unsigned 

intn = 1024;   

unsigned int

m = 0xff;  

其中1024和oxff這兩個常量都是有符號數,這就意味著每個賦值操作包含了乙個隱式的由有符號數到無符號數的型別轉換。

而1024u和0xffu則視為無符號數。

這樣的型別轉換是指不同字長的無符號數或有符號數之間的型別轉換,如由short轉為int,或是有unsigned short轉換為unsigned。

無符號數由短變長使用零擴充套件,使用0來填充多出來的高位元組。例:

[cpp]view plain

copy

unsigned 

char

a = 178;  

unsigned short

b = a;  

a的二進位制表示為1011,0010,b的二進位制表示為0000,0000,1011,0010,這就是零擴充套件。零擴充套件對於應彙編(ia32)指令movz。

有符號數一般使用補碼表示,有符號數的由短變長的轉換使用符號擴充套件,即較短的數的二進位制表示的最高位是0則用零擴充套件,同無符號數的零擴充套件,而如果是1,則用1來補充缺少的位。例:

[cpp]view plain

copy

char

a = -78;  

short

b = a;  

a的二進位制表示為1011,0010,b的二進位制表示為1111,1111,1011,0010。當然,此時b的大小仍是-78。

而由長變短則更簡單,直接截斷即可,高位的位元組直接丟掉,低位的位元組保持不變。

[cpp]view plain

copy

a = (

int)b; 

// 顯示的強制型別轉換

b = a;      // 轉換是隱式發生的

當發生有符號數和無符號數之間的強制型別轉換時,如果他們的長度是相同(比如int和unsigned一般都是4個位元組,short和unsigned short都是兩個位元組),那麼在位一級的表示上並沒有變化,即如果都轉化為二進位制的形式來看,都是一樣的。雖然從二進位制01組成的角度來看是一樣的,但我們要知道有符號數和無符號數的區別是最高位的權值發生了變化,有符號整數用補碼表示,最高位的權值是-2^(w-1),w為位寬,如int型別w大小為32,而無符號整數的最高為的權值為2^(w-1)。

而如果兩個數長度不同,則先進行前面提到的2中長度的轉換,再進行型別轉換。 例:

[cpp]view plain

copy

short

n = -1;  

unsigned short

m = 1;  

if(m > n) printf(

"m > n"

);  

else

printf(

"m < n"

);  

這樣可以得到什麼結果呢?

首先n轉化為無符號數,大小為65535,所以輸出是m

在1中我們說,如果乙個常數沒有字尾,那麼預設的是int型別,如果字尾是u,則預設為unsigned int。但這樣的說法並不完整。

首先,我們預設了常數的格式是十進位制,但是十六進製制的也很常用。

然後,還可能出現這樣的情況:給出的常數的值已經超越了int或是unsigned int的範圍。這種情況又該如何處理?

可能目前為止都沒有遇到過這種情況,但是如果發生該如何理解呢?別急,c標準對這些情形都給出了明確的說明,了解之後你就會知道為啥不知道也沒有發生錯誤。

看完下面這張表你也許悟到了點啥,莫名其妙也沒關係,讓我們來細說一例:

「十進位制常數」和「none」字尾的對應的格仔裡的內容是:

intlong int

long long int

這三行的意思是對於沒有字尾的十進位制常數,如1024和3147483647,首先用int型別來匹配,int型別值得範圍是-2147483648~2147483647(這裡可以看出有符號整型的範圍不是對稱的,而且此處預設int型別為32位),1024在此範圍之內,那麼這個常數的型別就是int了,但3147483647不在此範圍之內,即int型別罩不住,那麼看第二行, long int 型別, 其範圍還依賴於機器的字長,一般32位機上為

-2147483648~2147483647,還是罩不住,再看第三行,long long int,其範圍是

-9223372036854775808到

9223372036854775807

,所以3147483647最終匹配的型別是long long int。

對於八進位制或十六進製制的常數,如果沒有字尾,會先匹配有符號數,再匹配無符號數,畢竟從取值的絕對值的範圍的角度上看無符號數更廣。

如果乙個常數大的表中沒有任何型別能夠表示,那麼就要看有沒有擴充套件型別能夠表示它,如果沒有,那麼這個常數沒有型別。

-2147483648這個常數會是什麼型別?不一定是int型別,這還要看編譯器,很可能編譯器會把它當成乙個64位的有符號整型(可能是long long int),或者說該編譯器在識別常數時可能認為int型別的範圍是-2147483647~2147483647,但是我們應該知道32位的int型別是可以表示-2147483648。所以求int型別的絕對值也不那麼簡單,需要考慮這種情況。

suffix 

字尾decimal constant 

十進位制常數

octal or hexadecimal constant 

八或十六進製制常數

none

intlong int

long long int

intunsigned int

long int

unsigned long int

long long int

unsigned long long int

u or u

unsigned int

unsigned long int

unsigned long long int

unsigned int

unsigned long int

unsigned long long int

l or l

long int

long long int

long int

unsigned long int

long long int

unsigned long long int

both u or u

and l or l

unsigned long int

unsigned long long int

unsigned long int

unsigned long long int

ll or ll

long long int

long long int

unsigned long long int

both u or u

and ll or ll

unsigned long long int

unsigned long long int

C 有符號數和無符號數

1.有符號數和無符號數 c支援所有整形資料型別的有符號數和無符號數運算。儘管c標準並沒有指定某種有符號數的表示,但是幾乎所有的機器都使用二進位制補碼。通常,大多數數字預設都使有符號的,c也允許無符號數和有符號數之間的轉換,轉換原則是基本的位表示保持不變。因此在一台二進位制補碼機器上,當從無符號數轉換...

有符號數和無符號數

有符號和無符號整數 1.通常情況下,大多數字預設的是有符號數,比如 4,5 要想寫乙個無符號數必須在後面加u 比如 4u,5u 2.在計算機中有符號數是用補碼的形式來表示的,最高位是符號位。無符號數就是正數唄 正數的補碼和原碼相同。比如 1 在計算機中表示為 11111111 11111111 11...

無符號數和有符號數

人有十個手指頭,習慣了逢十進一,於是十進位製成了生活中的標準。程式的世界只有高低電平兩種狀態,更適合用二進位制來表示,於是二進位製成了程式世界的標準。對與無符號數來說,我們更喜歡談他們之間的轉化,十進位制是我們最習慣的進製,於是十進位制轉為r進製,r進製轉為十進位制變尤為重要。十進位制 r進製 整數...