假设我有一个签名的字符成员num = 15
,我做num = ~num
。然后,根据this帖子,我们将获得-16。
~(00001111) = (11110000)
但是,如果我将MSB视为符号位,那么答案不应该是-112
吗?怎么会导致-16?为什么忽略左边的第二个和第三个设置位。
任何人都可以澄清。
修改 我想更详细地解释为什么以下程序导致-16而不是-112
#include<stdio.h>
int main()
{
char num = 15;
num = ~num;
printf("%d\n", num);
return 0;
}
我希望它为1(1110000) = -(1110000) = -112
答案 0 :(得分:3)
~(00001111) = (11110000)
您正在做的是使用MSb(最高有效位)作为标志来决定放置一个“ - ”符号,然后正常读取其余位。相反,MSb是执行 2 事情的标志:放一个' - '符号 - 然后不是值并添加一个(2的补码) - 然后打印出其余的位。
这来自固定长度位值的溢出/下溢特性:
00000010 - 1 = 00000001 (2-1=1)
00000001 - 1 = 00000000 (1-1=0)
00000000 - 1 = 11111111 (0-1=-1)
答案 1 :(得分:3)
C允许三种不同的有符号整数表示,但最常见的是&#34;二进制补码&#34;。但是,我将简要讨论一下这个补充&#34;以及说明它们之间是如何存在关系的。
一个补码整数分为符号和值位。以整数19
的8位表示形式为例:
S|64 32 16 8 4 2 1
0| 0 0 1 0 0 1 1 = 19
使用按位补码运算符~
翻转整数的所有位,包括符号位:
S|64 32 16 8 4 2 1
1| 1 1 0 1 1 0 0 = ~19
当符号位置1时,1和0位的解释反转(0 =开,1 =关),该值被认为是负数。这意味着上面的值是:
-(16 + 2 + 1) = -19
与一个补码不同,整数不分为符号位和值位。相反,被视为符号位的内容会将-2^(b - 1)
添加到值的其余部分,其中b
是位数。要再次使用~19
的8位表示的示例:
-128 64 32 16 8 4 2 1
1 1 1 0 1 1 0 0 = ~19
-128 + 64 + 32 + 8 + 4
= -128 + 108
= -(128 - 108)
= -20
-19
的值在算术上比-20
多1,这遵循一个通用模式,其中两个补码中-n
的任何值总是比一个~n
的值,表示以下值始终适用于值n
:
-n = ~n + 1
~n = -n - 1 = -(n + 1)
这意味着您只需查看5位值15
,取消它并减去1即可获得~15
:
~15 = (-(15) - 1)
= -16
对于2的补码中的5位值, -16
表示为:
-16 8 4 2 1
1 0 0 0 0 = -16
使用~
运算符翻转位会产生原始值15
:
-16 8 4 2 1
0 1 1 1 1 = ~(-16) = -(-16 + 1) = -(-15) = 15
我觉得我应该提到关于两个补码的算术溢出。我将使用2位有符号整数的示例来说明。对于2位有符号整数,有2 ^ 2 = 4个值:-2,-1,0和1.如果您尝试否定-2
,它将无法工作:
-2 1
1 0 = -2
在普通二进制文件中编写+2
会产生1 0
,与上面-2
的表示相同。因此,对于2位有符号整数,+2
是不可能的。使用上面的等式也揭示了同样的问题:
// Flip the bits to obtain the value of ~(-2)
~(-2) = -(-2 + 1)
~(-2) = 1
// Substitute 1 in place of ~(-2) to find the result of -(-2)
-(-2) = ~(-2) + 1
-(-2) = 1 + 1
-(-2) = 2
虽然这在数学上是有道理的,但事实是2在可表示的值范围之外(仅允许-2,-1,0和1)。也就是说,将01加1(1)得到10(-2)。没有办法在硬件中神奇地添加一个额外的位来产生一个新的符号位位置,所以你得到一个算术溢出。
更一般地说,你不能否定一个整数,其中只有符号位用有符号整数的二进制补码表示。另一方面,你甚至不能在2位补码表示中表示-2之类的值,因为你只有一个符号位,另一位代表值1
;你只能用一个补码表示-1, -0, +0, and +1
值。