波浪号 C 无符号与有符号整数
Posted
技术标签:
【中文标题】波浪号 C 无符号与有符号整数【英文标题】:Tilde C unsigned vs signed integer 【发布时间】:2012-10-20 07:28:57 【问题描述】:例如:
unsigned int i = ~0;
结果:我可以分配给i
的最大数量
和
signed int y = ~0;
结果:-1
为什么我得到-1
?我不应该得到我可以分配给y
的最大数量吗?
【问题讨论】:
您确定您了解 ~ 运算符的作用吗? (按位非) 好吧,-1
是您可以放入整数的 最大 数,但 maximum 定义为绝对二进制值 :)
【参考方案1】:
4294967295
(又名UINT_MAX
)和-1
都具有0xFFFFFFFF
的相同二进制表示或32 位都设置为1
。这是因为有符号数使用two's complement 表示。负数的 MSB(最高有效位)设置为 1
,其值通过翻转其余位、加上 1
并乘以 -1
来确定。因此,如果您将 MSB 设置为 1
并且其余位也设置为 1
,则翻转它们(获得 32 个零),添加 1
(获得 1
)并乘以 -1
到终于得到-1
。
这使得 CPU 更容易进行数学运算,因为它不需要负数的特殊例外。例如,尝试添加0xFFFFFFFF
(-1) 和1
。由于只有 32 位空间,这将溢出,结果将如预期的那样为0
。
查看更多:
http://en.wikipedia.org/wiki/Two%27s_complement
【讨论】:
【参考方案2】:unsigned int i = ~0;
结果:我可以分配给 i 的最大数量
通常,但不一定。表达式~0
的计算结果为设置了所有(非填充)位的int
。 C 标准允许有符号整数的三种表示形式,
~0 = -1
并将其分配给 unsigned int
会产生 (-1) + (UINT_MAX + 1) = UINT_MAX
。
个数的补码,在这种情况下~0
是负零或陷阱表示;如果它是负零,则分配给 unsigned int
的结果为 0。
符号和幅度,在这种情况下~0
是INT_MIN == -INT_MAX
,并将其分配给unsigned int
会导致(UINT_MAX + 1) - INT_MAX
,在不太可能的情况下1
是1
具有宽度(无符号整数类型的值位数,有符号整数类型的值位数 + 1 [符号位])小于int
和2^(WIDTH - 1) + 1
在常见情况下unsigned int
的宽度为与int
的宽度相同。
初始化
unsigned int i = ~0u;
将始终导致 i
持有值 UINT_MAX
。
signed int y = ~0;
结果:-1
如上所述,只有当有符号整数的表示使用二进制补码时(这是目前最常见的表示)。
【讨论】:
【参考方案3】:~0
只是一个int
,所有位都设置为1。当解释为unsigned
时,这将等效于UINT_MAX
。当解释为signed
时,这将是-1
。
假设 32 位整数:
0 = 0x00000000 = 0 (signed) = 0 (unsigned)
~0 = 0xffffffff = -1 (signed) = UINT_MAX (unsigned)
【讨论】:
谢谢,但为什么 0xffffffff 是 -1 的签名? ~0 = 0xffffffff = -1(有符号,-1 为 2 的补码形式)。所有系统都遵循这种方法吗? 赋值不是重新解释,而是值转换:当~0
赋值给unsigned int
时,如果~0
类型为int
代表-1
,则只会产生UINT_MAX
我认为还值得注意的是,0 - 1
始终是 0xffffffff
,如果已签名则解释为 -1
,如果未签名则溢出到 UINT_MAX
。反之,0xffffffff + 1
始终为0
,如果有符号则再次正确,如果无符号则从UINT_MAX
溢出。
@hyde:这是不正确的 - 如果使用二进制补码,0xffffffff
仅表示 -1
,而在符号和幅度的情况下表示 -2147483647
,在反码的情况下表示 0
(但这可能是一个陷阱表示)【参考方案4】:
保罗的回答是绝对正确的。除了使用 ~0,您可以使用:
#include <limits.h>
signed int y = INT_MAX;
unsigned int x = UINT_MAX;
现在如果你检查值:
printf("x = %u\ny = %d\n", UINT_MAX, INT_MAX);
您可以查看系统上的最大值。
【讨论】:
【参考方案5】:不,因为~
是按位非 运算符,而不是类型的最大值 运算符。 ~0
对应于所有位设置为 1
的 int
,将其解释为无符号数会为您提供无符号数可表示的最大数,而将其解释为有符号整数则为 -1。
【讨论】:
【参考方案6】:您必须在two's complement 机器上。
【讨论】:
关于替代系统的简要讨论,以及它今天如何不被使用:en.wikipedia.org/wiki/Ones%27_complement#History C 语言允许二进制补码、二进制补码和符号幅度表示,基于底层硬件,所以它不是完全未使用的。如果有一些基于硬件的因素(速度或成本)来使用其他表示之一,我敢打赌他们会回来。【参考方案7】:查看http://en.wikipedia.org/wiki/Two%27s_complement,了解一些关于布尔代数和逻辑设计的知识。另外学习如何用二进制计数和用二进制加减法将进一步解释这一点。
C 语言使用这种形式的数字,因此要找到您需要使用的最大数字 0x7FFFFFFF。 (您使用的每个字节使用 2 个 FF,最左边的字节是 7。)要理解这一点,您需要查找十六进制数字及其工作原理。
现在解释无符号等价物。在有符号数中,数字的下半部分为负数(假设 0 为正数,因此负数实际上比正数高 1)。无符号数都是正数。所以理论上你的 32 位 int 的最高数字是 2^32,除了 0 仍然算作正数,所以它实际上是 2^32-1,现在对于有符号数,这些数字的一半是负数。这意味着我们将前一个数字 2^32 除以 2,因为 32 是一个指数,我们在每一边得到 2^31 个数字 0 为正数意味着有符号 32 位 int 的范围是 (-2^31, 2^31- 1).
现在只比较范围: 无符号 32 位整数:(0, 2^32-1) 带符号的 32 位整数:(-2^31, 2^32-1) 无符号 16 位整数:(0, 2^16-1) 带符号的 16 位整数:(-2^15, 2^15-1)
您应该能够在此处看到模式。 要解释 ~0 的事情需要多一点,这与二进制减法有关。它只是加 1 并翻转所有位,然后将两个数字加在一起。 C 在幕后为您执行此操作,许多处理器(包括 x86 和 x64 处理器系列)也是如此。 因此,最好将负数存储为倒数,并且在二进制补码中添加的 1 也被隐藏。因为 0 被假定为正数,所以负数不能有 0 的值,所以它们会自动添加 -1(位翻转后的正 1)。在解码负数时,我们必须考虑到这一点。
【讨论】:
以上是关于波浪号 C 无符号与有符号整数的主要内容,如果未能解决你的问题,请参考以下文章