无符号整数是如何工作的?

4

正如标题所示,我对于 unsigned int (或者像 NSUInteger, u_int_blah 这样的东西,但我猜这些都是同一种类型的 typedef)的工作方式很好奇。例如,当它们的值小于零时,会引发异常吗?会出现错误吗?其中一个具体的例子是间接地将值设置为一个负数。

for (unsigned int x = 5; x > -10; x--) {
    // will x ever reach below zero, or will the loop terminate
}

另一种间接设置它的方式是让用户输入。
printf("Enter a number");
unsigned int x;
scanf("%ud", &x); // user enters something like -29


实际上,我有三个问题。为什么无符号整数不能被赋值为负数(unsigned int x = -3)。这种行为是如何实现的(由编译器还是其他方式)。当无符号整数被直接或间接地赋值为负值时会发生什么。数据会损坏吗?会溢出吗?
谢谢


那个问题在询问无符号整数相减和相加时会发生什么。我想知道编译器如何执行它们以及当它们低于零时会发生什么。 - Brian Tracy
当“结果为负数”时,它是否不是在询问“减去无符号整数”? - Qantas 94 Heavy
我看到了相似之处,但我的问题中还涉及其他行为方面的问题。 - Brian Tracy
你在这里有几个不同的问题,对于将有符号数分配给无符号变量的情况,我的答案应该会有所帮助。如果我有更多时间,我会回来看看这个问题。 - Shafik Yaghmour
3个回答

3

当无符号数与有符号数进行比较时,它们都会被强制转换为无符号数。这个过程与数据在内存中的存储方式有关。 在二进制中,一个负数(如-3)将被存储为:

-3 : 1111 1111 1111 1101
3  : 0000 0000 0000 0011

你可以这样理解-3:
// result  : 0000 0000 0000 0011

result = for_every_bit_of_3( not **ThisBit** );  
// result  : 1111 1111 1111 1100 

result = result + 1;
// result  : 1111 1111 1111 1101 

所以这个循环:
for (unsigned int x = 5; x > -10; x--) {
    // will x ever reach below zero, or will the loop terminate
}

将会如下:

// 4,294,967,286 is what -10 cast to unsigned
for (unsigned int x = 5; x > 4294967286; x--) {
    // will x ever reach below zero, or will the loop terminate
}

2

当您分配一个负数时

unsigned int = -1;

你所得到的数字将是4294967295,或者说4的8次方减1。
这是因为整数变量的大小为4字节,也就是4的8次方等于4294967296。
如果整数是负数,则会在达到该数后重新回到最小值。

你可以想象一下,如果循环计数器变成了负数,那么它的值将会变成一个非常大的数字,如4294967295...4294967294...4294967293...等等。这不会导致程序崩溃,但你几乎无法得到你想要的正确结果。 - John

1
针对您的第一个代码示例,该循环将会编译通过(但如果您使用gcc编译且开启了-Wno-sign-compare标志,则会引发警告)。然而,运行它通常会导致循环根本不执行,因为大多数系统使用二进制补码(http://en.wikipedia.org/wiki/Two%27s_complement),这意味着-10与4294967286相同(假设整数为4字节,但通常情况下为2*INT_MAX-10),这比5大。一般来说,我建议您阅读有关二进制补码的资料,因为它可能会回答您在此问题上的所有疑问。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接