2013-12-12 27 views
1
#include<stdio.h> 
#include<conio.h> 
main() 
{ 
    int i=-5; 
    unsigned int j=i; 
    printf("%d",j); 
    getch(); 
} 

O/p 
----- 
-5 

#include<stdio.h> 
#include<conio.h> 
main() 
{ 
    int i=-5; 
    unsigned int j=i; 
    printf("%u",j); 
    getch(); 
} 

O/p 
=== 
4255644633 

這裏我沒有收到任何編譯錯誤。我們可以將整數與負數分配給無符號整數嗎?

使用標識符%d打印時發出-5,使用%u打印時正在打印一些垃圾值。

我想知道的事情是

1)爲什麼用負數unsigned int類型分配整數時,編譯器會忽略。

2)它如何將簽名轉換爲無符號?

+0

如果你打開警告,編譯器會警告你,你正在分配一個簽名給一個無符號。編譯器只是複製數字。所以符號位最終成爲未簽名情況下的數字的一部分。所以如果給一個無符號數賦一個負數「n」,你會得到一個大數字「2^32- | n |'(如果它是一個32位的字)或'2^64- | n |'如果它是一個64位字。 – lurker

+2

我看到令人困惑的是,在二進制補碼中,'-5'應該是'4294967291',而不是'4255644633'。我在'gcc'中籤出,這確實是我得到的價值。我不明白他如何獲得不同的價值。 –

+2

@ user3095972:您發佈的第二個代碼無法輸出「4255644633」。您要麼發佈錯誤的代碼,要麼發佈錯誤的輸出。 – AnT

回答

2

誰是「我們?」

沒有「垃圾值」,它可能只是將有符號整數的位視爲無符號的結果。通常two's complement將導致很多負值的非常大的值。嘗試打印十六進制值以更清晰地查看模式,十進制數字通常難以破譯。

+1

小調:值*非*「接近0」也會*顯示非常大的值 - 至少2^31 -1或2,147,483,648。 (在32位整數系統上,64位系統將顯示更高的值。) – usr2564301

+0

@Jongware真的,我刪除了那一點。謝謝。 – unwind

0

根據編譯器和設置,您可以和您得到警告(或者可能失敗)。

您得到的價值是由於二補。

+0

-1從signed到unsigned的轉換遵循明確定義的轉換。這些不應該給予警告,在任何情況下都不能編譯失敗。 –

+0

@JensGustedt - 我沒有提到它沒有很好的定義。但是你可以配置VS失敗而不是發出警告。請參閱#pragma –

1

有沒有不尋常的可能性爲一個無符號變量分配一個負值。在這種情況下發生的隱式轉換完全由C語言定義。根據模算術的規則將該值帶入目標無符號類型的範圍。模數等於2^N,其中N是未簽名收件人中的值位數。這就是它一直在C.

打印一個unsigned int值與%d說明是沒有意義的。該說明符需要參數signed int。由於這種不匹配,你的第一個代碼的行爲是不確定的。

換句話說,你完全倒退了哪些值是垃圾,哪些不是垃圾。

您的第一個由於未定義的行爲,代碼基本上是「打印垃圾值」。它恰好與您的原始值-5相符的事實只是未定義行爲的具體體現。

同時,第二個代碼應該打印一個明確定義的正確值。它應該是-5unsigned int類型的模UINT_MAX + 1的轉換結果。在你的情況下,模可能碰巧是2^32 = 4294967296,這就是爲什麼你應該看到4294967296 - 5 = 4294967291

如何設法獲得4255644633尚不清楚。您的4255644633顯然是不同代碼的結果,而不是您發佈的代碼。

+1

我唯一不理解的是'2^32'不是'4255644638',它是'4294967295'。我不知道他爲什麼得到那個價值。 –

+0

@Paulo Bu:你說得對。我被這篇文章弄糊塗了,簡單地將5 + 1加到輸出:)顯然,OP的輸出是由不同的代碼生成的。 – AnT

0

在第二情況下的輸出是不是一個垃圾值...

int i=-5; 

當轉換爲二進制形式的最高有效位被分配「1」作爲-5是負數..

但是當u使用%U的二進制形式被視爲正常的數量和在MSB 1被處理過的正數的一部分。這

2

我只添加的概念符號或無符號是人類比機器更欣賞的東西。

假設一個32位的機器,你的-5的值將在內部由32位值0xFFFFFFFB(二進制補碼)表示。

printf("%d",j);插入源代碼時,編譯器無需關心j是帶符號還是無符號,它只是將0xFFFFFFFB推入堆棧,然後指向"%d"字符串。當有呼叫時printf功能着眼於格式字符串,看到%d並從它已經到解釋的0xFFFFFFFB作爲簽署價值,因此對於儘管j它顯示-5是一個unsigned int的理由知道。

在另一方面,當你寫printf("%u",j);,該"%u"使printf解釋你0xFFFFFFFB作爲無符號值。該值爲2^32 - 5或4294967291.

這是傳遞給printf的格式字符串,它決定如何解釋該值,而不是變量j的類型。

+0

終於有人理解了這個話題,並沒有對「符號位」做出模糊的陳述! +1 – Ingo

+0

相反,在這個答案中給出的第一個代碼的行爲的解釋只是試圖挑選未定義行爲的具體表現。鑑於現代編譯器開發的狀態(例如高級格式錯誤檢查和'printf'是GCC中的內置函數,舉一個例子),這種解釋可能被證明是完全不準確的。第一個代碼被破壞,這就是它的全部。 – AnT

+0

從C語言的角度來看,第二種解釋是不正確的。 C語言定義了語言級的符號 - 無符號轉換的行爲,並且定義非常完美,不需要引入任何2的補碼位模式。說第二種情況的行爲僅僅是因爲結果碰巧是'0xFFFFFFFB'是誤導和不正確的。它只會被閱讀到更困惑的道路上。 – AnT