Tilde C unsigned vs signed integer

时间:2012-10-30 21:23:54

标签: c operators bit-manipulation tilde

例如:

unsigned int i = ~0;

结果:我可以分配给i

的最大数量

signed int y = ~0;

结果-1

为什么我会-1?我不应该获得可以分配给y的最大数量吗?

7 个答案:

答案 0 :(得分:7)

4294967295(a.k.a。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

答案 1 :(得分:5)

unsigned int i  = ~0;
  

结果:我可以分配给我的最大号码

通常,但不一定。表达式~0的计算结果为int,并设置了所有(非填充)位。 C标准允许对有符号整数进行三次表示,

  • 两个补码,在这种情况下~0 = -1并将其分配给unsigned int会产生(-1) + (UINT_MAX + 1) = UINT_MAX
  • 1'补码,在这种情况下~0是负零或陷阱表示;如果它是负零,则unsigned int的分配将导致0。
  • 符号和幅度,在这种情况下,~0INT_MIN == -INT_MAX,并将其分配给unsigned int会产生(UINT_MAX + 1) - INT_MAX,其中1unsigned int具有宽度(无符号整数类型的值位数,有效位数+ 1 [对于有符号整数类型的符号位])小于int和{的不太可能的情况{1}}通常情况下2^(WIDTH - 1) + 1的宽度与unsigned int的宽度相同。

初始化

int

始终会unsigned int i = ~0u; 保持值i

UINT_MAX
  

结果:-1

如上所述,只有当有符号整数的表示使用二进制补码时(现在是最常见的表示)。

答案 2 :(得分:4)

~0只是一个int,所有位都设置为1.当解释为unsigned时,这将等同于UINT_MAX。如果解释为signed,则为-1

假设32位整数:

 0 = 0x00000000 =  0 (signed) = 0 (unsigned)
~0 = 0xffffffff = -1 (signed) = UINT_MAX (unsigned)

答案 3 :(得分:2)

保罗的回答是完全正确的。您可以使用:

而不是使用〜0
#include <limits.h>

signed int y = INT_MAX;
unsigned int x = UINT_MAX;

现在,如果你检查值:

printf("x = %u\ny = %d\n", UINT_MAX, INT_MAX);

您可以在系统上看到最大值。

答案 4 :(得分:1)

不,因为~按位NOT 运算符,而不是类型运算符的最大值。 ~0对应于int,所有位都设置为1,解释为无符号,为您提供无符号可表示的最大数字,并解释为带符号的int,为您提供 - 1。

答案 5 :(得分:0)

您必须在two's complement机器上。

答案 6 :(得分:0)

查找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位int:(0,2 ^ 32-1) 签名32位int:( - 2 ^ 31,2 ^ 32-1) 无符号16位int:(0,2 ^ 16-1) 签名16位int:( - 2 ^ 15,2 ^ 15-1)

你应该能够看到这里的模式。 解释〜0的事情需要多一点,这与二进制中的减法有关。它只是添加1并翻转所有位然后将两个数字相加。 C在幕后为您完成此操作,许多处理器(包括x86和x64系列处理器)也是如此。 因此,最好存储负数,就好像它们正在倒计时一样,并且在二进制补码中,添加的1也是隐藏的。因为0被假定为正,因此负数不能具有0的值,因此它们自动地将-1(位翻转后的正1)添加到它们。在解码负数时,我们必须考虑到这一点。