2010-09-12 202 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。