【发布时间】:2011-04-23 08:35:17
【问题描述】:
为什么签名字符的范围是-128到127而不是-127到128?
【问题讨论】:
标签: c
为什么签名字符的范围是-128到127而不是-127到128?
【问题讨论】:
标签: c
在 8 位 2 的补码编码中,-128 和 +128 具有相同的表示:10000000。因此,硬件设计者面临一个明显的困境:如何解释位模式10000000。形式上,它会以任何一种方式工作。如果他们决定将其解释为+128,则结果范围将为-127..+128。如果他们决定将其解释为-128,则结果范围将为-128..+127。
在现实生活中 2 的补码表示中,选择后一种方法是因为它满足以下很好的约定:所有具有高位 1 的位模式表示负数。
值得注意的是,语言规范不需要 2 的补码实现来将 100...0 位模式视为任何有符号整数类型中的有效值。例如。允许实现将 8 位 signed char 限制为 -127..+127 范围,并将 10000000 视为无效位组合(陷阱表示)。
【讨论】:
如果您查看 chars 和 int 的范围,则在负数方面似乎有一个额外的数字。这是因为负数始终存储为其二进制的 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 位数字。
【讨论】:
#include <limits.h>
#include <stdio.h>
...
printf("range of signed character is %i ... %i", CHAR_MIN, CHAR_MAX );
【讨论】:
我认为为共同的灵魂解释这一点的一个简单方法是:
一个位是一个值0 或1,或两种可能性
2 位包含两个组合或 0 和 1 四个可能的值:00、01、10 和 11。
一个 3 位包含三个组合,总共有八个可能的值:000 到 111。
因此,n 位包含 n 个组合,总共有 2^n 个可能的值。因此,一个 8 位的值是 2^8 = 256 个可能的值。
对于有符号数,最高有效位(从左到右读取值的第一个)是符号位;这留下了 2^(n-1) 个可能值的可能性。对于 8 位有符号数,每个符号有 2^7 = 128 个可能值。但是由于正号包括零(0 到 127 = 128 个不同的值,并且 128 + 128 = 2^8 = 256),负号也包括 -1 到 ... -128 的 128 个不同的值。哪里:
10000000 = -128
...
11111111 = -1
00000000 = 0
...
01111111 = 127
【讨论】:
如果您只是将二进制补码视为算术模 256,那么正负之间的截止值纯粹是任意的。您也可以将其设置为 63/-192、254/-1、130/-125 或其他任何位置。然而,作为标准的有符号整数格式,二进制补码按照惯例将截止值设置为 127/-128。这个截止有一个很大的好处:设置的高位直接对应于负数。
对于C语言,它把有符号数的格式留给实现,但只提供了3种实现选择,所有这些选择都使用“符号位”:符号/大小、一个补码和二进制补码。
【讨论】:
这是因为two's complement 编码的工作方式:0 被视为“正”数(有符号位关闭),因此,可用正值的数量减少了 1。
在ones' complement 编码中(这在现在并不常见,但在过去很常见),+0 和 -0 有不同的值,因此 8 位数量的范围是 -127到 +127。
【讨论】: