签名字符范围

为什么有符号字符的范围是-128127而不是-127128

这是因为二进制补码编码的工作方式:0被视为“正”数(有符号位关),因此,可用正值的数量减少了一个。

在一些补码编码中(现在不是很常见,但在过去,它是),+ 0和-0有单独的值,因此8位数量的范围是-127到+127 。

在8位2的补码编码中, -128+128具有相同的表示: 10000000 。 因此,硬件设计者面临一个明显的困境:如何解释位模式10000000 。 在forms上,它将以任何一种方式工作。 如果他们决定将其解释为+128 ,则结果范围将为-127..+128 。 如果他们决定将其解释为-128 ,则结果范围将为-128..+127

在实际的2的补码表示中,选择后一种方法是因为它满足以下良好的约定:所有在高阶位中具有1位模式表示负数。

值得注意的是,语言规范不要求二进制补码实现将100...0位模式视为任何有符号整数类型中的有效值。 例如,允许实现将8位带signed char限制为-127..+127范围,并将10000000视为无效位组合(陷阱表示)。

我认为一个简单的方法来解释这个共同的灵魂是:

位是值01 ,或2种可能性

对于四个可能的值,2位保持两个组合或010011

3位保持三种组合,总共八个可能的值: 000111

因此,n位保持n个组合,总共2 ^ n个可能的值。 因此,8位值是2 ^ 8 = 256个可能的值。

对于带符号的数字,最高有效位(从左到右读取值的第一个)是符号位; 这留下了2 ^(n-1)个可能值的可能性。 对于8位有符号数,对于每个符号,这是2 ^ 7 = 128个可能的值。 但由于正号包括零(0到127 = 128个不同的值,以及128 + 128 = 2 ^ 8 = 256),因此对于128个不同的值,负号包括-1到…… -128。 地点:

 10000000 = -128 ... 11111111 = -1 00000000 = 0 ... 01111111 = 127 
 #include  #include  ... printf("range of signed character is %i ... %i", CHAR_MIN, CHAR_MAX ); 

如果你只考虑二进制补码作为算术模256,那么正负之间的截止是纯粹随意的。 您也可以把它放在63 / -192,254 / -1,130 / -125或其他任何地方。 但是,作为标准的有符号整数格式,通过惯例将二进制补码放在127 / -128。 这个截止值有一个很大的好处:设置的高位直接对应于负数。

至于C语言,它将签名数字的格式留给实现,但只提供3种实现选择,所有这些选择都使用“符号位”:符号/幅度,补码和二进制补码。

如果你看一下字符和整数的范围,那么在负面看来似乎还有一个额外的数字。 这是因为负数始终存储为2的二进制补码。 例如,让我们看看如何存储-128。 首先,计算128的二进制(10000000),然后获得其1的补码(01111111)。 通过将所有0更改为1并将1更改为0来获得1的恭维。 最后,存储了这个数字的2个补码,即10000000。 通过在1的赞美中加1来获得2的赞美。 因此,对于-128,10000000被存储。 这是一个8位数字,可以轻松容纳在字符中。 与此相反,+ 128不能存储在char中,因为它的二进制010000000(最左边的0表示正号)是一个9位数。 但是可以存储+127,因为它的二进制01111111结果是8位数。