2013-01-09 79 views
1

我寫了一個小程序在下面。爲什麼char a = -1與unsigned char b = -1不同,在C編程中

#include <stdio.h> 
main(){ 
    char a=-1; 
    unsigned char b=-1; 
    printf("%d %d\n",a,b); 
    printf("%x %x\n",a,b); 
    if(a==b) printf("equal\n"); 
    else printf("not equal\n"); 
} 

的PROG的輸出是:

-1 255 
ffffffff ff 
not equal 

因爲焦炭是隻有一個字節和-1是在2的補碼形式表示的,我認爲,0xff的將被存儲在兩者& B和因此兩者應該是平等的。任何人都可以讓我知道爲什麼他們不同,爲什麼十六進制的rep'n是0xffffffff &不是0xff。我有一個相關的鏈接http://embeddedgurus.com/stack-overflow/2009/08/a-tutorial-on-signed-and-unsigned-integers/,但我無法得到答案。任何幫助將不勝感激。謝謝。

回答

5

它們是相同的。或者說,它們的底層表示方式是相同的(假設您的編譯器使用雙補碼形式)。

在另一方面,他們所代表的值是-1和255

當你打印出來,他們是擴展的數據類型intunsigned char是零擴展的,而有符號的char是符號擴展的,這說明了你所看到的差異。

當您比較兩個值時,會發生相同的擴展名。 a == b不會比較底層表示,而是將兩個值都擴展到int,因此它將255與-1進行比較,該值不相等。

請注意,一個普通的char可能是有符號的或無符號的。在你的環境中,它顯然是有簽名的。

+0

你告訴char類型在符號比較中被擴展爲int類型。我有兩個疑問:1)這樣的符號類型擴展到int類型是否總是在任何表達式中發生? 2)類似的擴展會發生int類型的short int嗎?我從來不知道C這樣的事情,你能否指出一些相同的鏈接。 – mezda

+0

在C中,所有操作*概念上*都出現在int中(或者更大,可能是無符號類型)。但是,在大多數操作中,操作可以減少到較小的機器操作。具體地說,無論操作是在8位還是在32位中執行,如果只使用低8位,那麼添加兩個char:會得到相同的結果。 2)是的,這發生在所有較小的整數類型上。 C中常見的「gotcha」是檢查一個無符號字符是否使用'〜ch == 0'設置了所有的位。這總是錯誤的,因爲'ch'將被零擴展爲'int'。 – Lindydancer

+0

這看起來不正確。根據類型提升的規則,'unsigned char'被提升爲'unsigned int',只有'signed char'被提升爲'int'(見ISO C標準)。根據隱式類型轉換規則,將'int'與'unsigned int'進行比較會導致兩個值都被轉換爲'unsigned int'。所以正確的答案應該是:它將兩個值擴展到'unsigned int',而不是'int'。 – Mecki

2

char類型是異常的的東西是不一樣的兩種signed charunsigned char(不像其他整數類型 - shortintlong,等等 - 這是隱含簽署,除非明確聲明unsigned)。 char是否實際簽名是實現相關的,有些編譯器甚至允許您通過命令行開關指定簽名。

底線:從不假定char帶符號 - 如果你真的需要一個符號或無符號的8位數量,然後使用signed charunsigned char明確,或者更好的是,使用int8_tuint8_t<stdint.h>

+0

顯然,在OP的實現中,'char'是有符號的,否則就沒有問題了。這個答案帶來了重要的信息,但並沒有回答原來的問題。 –

+0

@Pascal:true - 我錯誤地認爲OP理解有符號整數行爲和無符號整數行爲,並且對非限定字符變量的性質感到困惑。 –

2

A signed int已簽名,unsigned int未簽名。如果您僅使用int,則暗示signed intshort,longlong long也是如此。然而這不是char。 A signed char已簽名,unsigned char未簽名,但只有char可能有符號或無符號。數據類型char應該包含一個「字符」,即名稱,所以它不是「真正」的整數類型,用於保存要在計算中使用的整數。當然,角色實際上是一種某種類型的整數,但是哪種類型是實現相關的(C標準不強制任何特定類型)。所以如果你想使用整數值的字符類型(也用於計算),當你真的在處理字符或者它對你的代碼完全沒有區別的時候,總是使用signed charunsigned char,並且只使用char如果字符是有符號或無符號。因爲你實現定義char是事實上signed char

比較失敗,讓你在你的最終if聲明比較一個signed charunsigned char。無論何時您比較兩個不同類型的整數,編譯器都會在實際執行比較之前將這兩個值轉換爲相同類型的according to the rules of the C standard。在你的情況,這意味着C編譯器實際上做壽如下:

if((int)a==(int)b) printf("equal\n"); 
    else printf("not equal\n"); 
} 

而現在它應該是顯而易見的,爲什麼這兩個值不匹配。 (int)a的值爲-1,但(int)b的值爲255,並且這兩個值不相等。

類型提升規則,char(在你的情況下籤署的)晉升爲intunsigned char也被晉升爲int。在ISO C 2011標準表示:

如果int可以表示原始類型的所有的值(如限制 由寬度,對於一個位字段),該值被轉換爲int; 否則,它被轉換爲一個unsigned int。這些被稱爲 整數促銷。)所有其他類型都是不變的整數 促銷。

整數提升保存值包括符號。如前面討論的 ,是否將一個「普通」字符視爲有符號的是實現定義的 。

+0

與Paul R的答案相同,這是一個重要的信息,但並沒有回答這個問題。 ''char'由OP的實現明確定義爲'signed'。 –

+0

@Mecki:謝謝你的回覆。你的答案與Lindydancer的答案不同,因爲你說這兩個值都將被轉換爲unsigned int(所以我們將比較4294967295與255),而她說這兩個值都將被轉換爲int(這樣我們就會將-1與255)。你能否詳細說明這裏的正確性?謝謝... – mezda

+0

一個'unsigned char'被提升爲一個普通的帶符號的'int'(§6.3.1.1),所以得到的操作將以'int'類型執行。對於'=='無關緊要,但如果使用另一個比較操作(如'<'),則會出現這種情況。 – Lindydancer

0

雖然圍繞一個普通的「字符」(見Is char signed or unsigned by default?)有一些不明確之處,但這並不是我在這裏想到的唯一事情。

一個文字-1是一個整數,它不會(sizeof(int)> sizeof(char),爲了參數的緣故)「適合」到一個char。雙補碼模式0xffff(32位int for參數的緣故)被截斷並複製到這裏。

當您調用printf()參數被提升爲整數類型時,有符號類型是「符號擴展」,但無符號「b」不是,並且零填充。當你使用兩個不同類型的「==」時,類似的(但不一定是相同的)類型轉換被執行(又稱「通常的算術轉換」)。請參閱Default argument promotions in C function callsSigned and unsigned, and how bit extension works in C

相關問題