我正在学习C语言,有一个关于无符号int和有符号int的值范围中的“-1”的愚蠢问题。我似乎在任何地方都找不到它的解释。
下面的段落解释了数据范围。但是,它没有解释“-1”。“-1”代表/意味着什么?是因为它跳过了0而0没有值所以它是-1吗?
在32位整数中,无符号整数的范围为0到2^32 -1 = 0到4,294,967,295,约为40亿。有符号整数的范围为-2^31 -1到2^31,即-2,147,483,648到2,147,483,647,约为-20亿到+20亿。范围相同。但在数轴上移位。
5条答案
按热度按时间blmhpbnm1#
n位可以表示2n个不同的值。(第一位可以有两个值 * 第二位可以有两个值 * 第三位可以有两个值 *...)
例如,3个比特可以形成23 = 8个不同的比特模式,因此可以形成多达8个不同的值。
如果每个位模式表示一个整数,则n位整数可以表示2n个不同的整数。例如,
(因为(2n-1)-(0)+1 = 2n个不同的值)。
例如,
(因为(2n-1-1)-(-(2n-1))+1 = 2n个不同的值)。
例如,
你可以给这些值赋予任何意义,但前面所述的范围是二进制补码机器分别理解的无符号整数和有符号整数的范围。[1]
1.在ones'-complement机器上,有两种写零的方式(0000...00002和1000...00002),所以范围只有-(2n-1-1)到2n-1-1。
dldeef672#
加上@Yunnosch对无符号数的出色解释,几乎所有现代计算机都使用“二进制补码”来表示有符号二进制整数。在二进制补码中,最高有效位被用作“符号位”,位是数的绝对值+ 1的补码。因此,对于3位的示例,虽然无符号值的范围是0到7,有符号值的范围是-4到3:
请注意,对于有符号数,负数的值域比正数的值域大1。这是因为,在数论中,
0
既不是正数也不是负数,但在二进制表示中,0
必须是负数或正数。因为它的最高有效位被清除,所以0
是正数定义域的一部分。这样就少了一个正数。pn9klfpd3#
对于无符号整数类型,值-1超出范围,无法在该类型的变量中表示。如果尝试将-1赋给
unsigned int
,则会根据C标准的规则发生转换。有符号值到无符号整数类型的转换在C standard:
否则,如果新类型是无符号的,则通过重复地在新类型中可以表示的最大值上加一或减一来转换值,直到该值在新类型的范围内。60
...
60)这些规则描述的是数学值的算术运算,而不是给定类型表达式的值
假设
unsigned int
的取值范围为0到4,294,967,295,则值-1的转换方法是:将-1 + 4,294,967,296相加= 4,294,967,295。请注意,无论负数在给定的系统中如何表示,都会发生此转换。对于二进制补码、一进制补码、或符号和幅度。注意,这意味着转换值的表示不必与-1的表示相同。
以4位类型为例,将值-1转换为无符号类型会得到值15。这些数字的表示形式如下:
在二进制补码的情况下,转换的结果保持相同的表示形式,而在其他两种情况下,转换的结果发生变化。对于一进制补码,-1的表示形式与14相同,对于符号和量值,-1的表示形式与9相同。
因此,关于2的补码,其他答案所描述的最有可能是这些实现是如何做的(即,将-1的表示重新解释为无符号值),然而,从C语言作为抽象机器的Angular 来看,我所描述的是执行这种转换的唯一正确方法。
mhd8tkvw4#
你在哪里找到这个不正确的段落?它似乎是关于2的补码,但有一个
-1
在错误的位置。对于使用1的补码或符号/幅度有符号整数的C实现,范围围绕零对称(具有均表示
0
的2个位模式,因此正范围和负范围大小相同)。现在基本上没有什么东西使用它,但是ISO C标准规定有符号整数是二进制的,并且使用二的补码、一的补码或符号/幅度。
在2's complement(现在几乎是通用的)中,使用n位表示的值的范围是[- 2n-1,2n-1 - 1 ]。一个位模式(所有位都是零)表示值零。每个位都有一个位值
2^i
,除了最后一位的位值-2^(n-1)
。由于
sum(2^i, i=0..n-1)
比2^n
小1,因此所有位都已设置的位模式表示-1
。仅 * 设置符号位,我们得到最大负数:
-INT_MIN
是有符号溢出(未定义的行为),因为它不能表示为int
;它需要一个更宽的整数。或者带换行,-INT_MIN = INT_MIN
。这是“2的补码异常”。https://en.wikipedia.org/wiki/Two%27s_complement#Most_negative_number如果执行绝对值运算,则可以避免加宽:例如:
unsigned abs = i >= 0 ? i : -(unsigned)i;
(在C语言中,将一个负值转换为
unsigned
具有明确定义的模约简行为,直到它在可表示的范围内。在C语言中,这与符号整数编码无关;重要的是 value。所以(uint8_t)-1
* 总是 * 255。对于2的补码,它只是复制了位模式。对于符号/大小或1的补码,C实现将不得不做一些数学运算来从有符号转换为有符号。注意,我在 * 求反之前 * 做了这个运算,这意味着0 - i
带有通常的无符号 Package 。)kpbwa7wx5#
请考虑使用2位可以实现的值:
一共有4个,2的2次方。
但最高值不是4,是3。
最大值为2的2次幂减1。即在您的表示中
2^2-1
或22-1
加一点,你会得到两倍的数字。
总人数8人,但最高人数7人。
所以“-1”是因为总数2n中的第一个总是用于0,
第二个用于1,第三个用于2。
最后,第(2n)个不可用于2n,它已经用于2n-1。