2010-09-12 203 views
4

假設您有以下C代碼。澄清需要按位不(〜)運算符

unsigned char a = 1; 

printf("%d\n", ~a); // prints -2 
printf("%d\n", a); // prints 1 

我驚訝地發現-2印刷爲〜1個變換的結果:

的0000 0001相對的是1111 1110即是什麼,但-2。

我在這裏錯過了什麼?

+2

以二進制寫入0和-1的值。 – 2010-09-12 18:19:51

+3

「1111 1110 - >除了-2之外的任何東西」你在哪裏得到這個?這完全是二進制補碼。 – recursive 2010-09-12 18:19:59

+0

嘗試'print(「%x」)' – pmg 2010-09-12 18:22:37

回答

10

它是二的補碼。在二進制補碼錶示中,如果數字x的最高有效位是1,那麼實際值將是−(〜x + 1)。

例如,

0b11110000 = -(~0b1111 + 1) = -(15 + 1) = -16. 

這是負數的自然表示,因爲

0000001 = 1 
0000000 = 0 
1111111 = -1 (wrap around) 
1111110 = -2 
1111101 = -3 etc. 

參見http://en.wikipedia.org/wiki/Two%27s_complement詳細。


順便說一句,爲了打印一個無符號的值,使用%hhu%hhx格式。見http://www.ideone.com/YafE3

4

%d代表有符號的十進制數,不是無符號的。所以你的位模式,即使它存儲在一個無符號變量中,也被解釋爲一個有符號數。

查看此Wikipedia entry on signed number representations瞭解位值。具體見Two's complement

+1

但是在調用可變參數函數時,'unsigned char'通常比'unsigned int'更容易提升爲'int',所以'%d'在這種情況下可能是正確的格式規範。 – 2010-09-12 18:40:24

+1

但是,在發生按位否定之前,將'unsigned char'提升爲'int'。之後您必須重新轉換爲'unsigned char',以便按照需要工作。 – 2010-09-12 18:47:40

0

想到有符號數學的一種(輕度幽默)方法是認識到最重要的位實際上代表了無限多個位。所以在16位有符號數中,最高有效位是32768 + 65536 + 131072 + 262144 + ...等。 (1 + X + X^2 + X^3 + ...)= 1 /(1-X)是32768 *(1 + 2 + 4 + 8 + ...) ),發現(1 + 2 + 4 + 8 + ...)是-1,因此所有這些位的總和是-32768。