我曾认为unsigned int只能存储大于等于0的整数。
但是当我尝试将负数赋值给unsigned int时,似乎没有发生任何特殊情况。
看上去它毫无问题地存储了该值。
那么signed和unsigned int有什么区别呢?既然unsigned int可以存储任何值,那有什么意义呢?
像这样的语句
unsigned int t = -1;
printf("%u", t);
以上程序的输出是一个无符号值。6.3.1.3 有符号和无符号整数
(2) 否则,如果新类型是无符号的,则通过重复加上或减去一个比新类型中最大可表示值还大的值,直到该值在新类型的范围内为止,对该值进行转换。
4294967295
您可以将“负”值分配给无符号整数类型,但其实际意义并不是负值。当您将无符号整数值与负值进行比较时,这尤其重要。例如,请考虑以下两个循环:
int i = 10;
while (--i >= 0) { // 10 iterations
printf("i: %d\n", i);
}
unsigned int u = 10;
while (--u >= 0) { // endless loop; warning provided.
printf("u: %u\n", u);
}
u >= 0
始终为真。unsigned long
这样的无符号类型的正数范围是被允许相同的。例如,ULONG_MAX == LONG_MAX
,即使ULONG_MAX/2 == LONG_MAX
更为常见。我已经很多年没有看到过任何平台使用这个过时的特性,因为它意味着一个有填充的无符号类型,并且肯定不会再见到。 - chux - Reinstate MonicaintN_t
和一个(N-1)位无符号数,因为"符号"位是填充位。这与处理器本地支持有符号的*,/
有关,但不支持无符号的。今天,这样的模型会受到用户社区的太多反对,而且我们今天没有看到它,这意味着达尔文压力将其归入了计算机坟墓。所以即使被允许,也不是一个实际的问题,就像一只独角兽26位浮点数。 - chux - Reinstate Monicaunsigned int
只能存储大于等于0的整数。(当然,还有一个上限,这个上限取决于您的架构,并在limits.h中定义为UINT_MAX
。)int
值赋给unsigned int
,您正在调用隐式类型转换。C语言对此有一些非常精确的规则。尽可能保留值是编译器的首要任务。例如:int x = 5;
unsigned int y;
y = x;
y
也将具有值为 5。x = -5;
y = x;
unsigned int
范围内,因此编译器必须将该值转换为范围内的某个值。C 标准规定,将值 1 + UINT_MAX
加到该值上,直到它在 unsigned int
范围内。在大多数系统上,UINT_MAX
定义为 4294967925(2^32 - 1),因此 y
的值实际上将是 4294967921(或十六进制中的 0xFFFFFFFB)。signed int
值为 -5 的二进制表示也是 0xFFFFFFFB,但这不是必需的。C 标准允许并支持使用不同整数编码的机器,因此可移植代码不应假定在这种隐式转换后二进制表示将被保留。 (unxigned_c = unsigned_a + unsinged_b) >= UINT_MAX
然后unsigned_c
将会对UINT_MAX+1
取模:
#include <limits.h>
#include <stdio.h>
int main()
{
printf("%u\n", UINT_MAX+1); //prints 0
printf("%u\n", UINT_MAX+2); //prints 1
printf("%u\n", UINT_MAX+3); //prints 2
}
当你把有符号的值存储到无符号中时,类似的情况会发生。在这种情况下,适用于6.3.1.3p2 -- 概念上将UINT_MAX+1
添加到该值中。
而对于有符号类型,溢出是未定义的,这意味着如果你允许它发生,你的程序就不再是良构的,标准对其行为不做任何保证。编译器利用此进行优化,假设它永远不会发生。
例如,如果你编译
#include <limits.h>
#include <stdio.h>
__attribute__((noinline,noclone)) //or skip the attr & define it in another tu
_Bool a_plus1_gt_b(int a, int b) { return a + 1 > b; }
int main()
{
printf("%d\n", a_plus1_gt_b(INT_MAX,0)); //0
printf("%d\n", INT_MAX+1); //1
}
-O3
的gcc编译时,很可能会打印出以下内容。1
-2147483648
int main(){ unsigned int a = -1; if( 2U < a ){ printf("2 < '-1'\n"); }}
- datenwolf