无符号和有符号整数的比较运算

时间:2010-01-18 09:21:09

标签: c gcc unsigned signed

请参阅此代码段

int main()
{ 
 unsigned int a = 1000;
 int b = -1;
 if (a>b) printf("A is BIG! %d\n", a-b);
 else printf("a is SMALL! %d\n", a-b); 
 return 0;
}   

这给出了输出:a是SMALL:1001

我不明白这里发生了什么。怎么>在这里工作?为什么“a”小于“b”?如果它确实更小,为什么我得到一个正数(1001)作为差异?

7 个答案:

答案 0 :(得分:46)

不同整数类型之间的二进制操作在由所谓的通常的算术转换定义的“公共”类型中执行(参见语言规范,6.3.1.8)。在您的情况下,“常见”类型为unsigned int。这意味着int操作数(您的b)将在比较之前转换为unsigned int,以及执行减法。

-1转换为unsigned int时,结果是最大可能的unsigned int值(与UINT_MAX相同)。毋庸置疑,它会比您的未签名1000值更大,这意味着a > b确实是假的,a确实与{{{ 1}}。代码中的(unsigned) b应解析为if分支,这是您在实验中观察到的内容。

相同的转换规则适用于减法。您的else实际上被解释为a-b,结果的类型为a - (unsigned) b。由于unsigned int仅适用于已签名的值,因此无法使用%d格式说明符打印此类值。您尝试使用%d打印它会导致未定义的行为,因此从C语言的角度来看,您看到的打印值(即使它在实践中具有逻辑确定性解释)完全没有意义。

编辑:实际上,我对未定义的行为部分可能是错误的。根据C语言规范,相应的有符号和无符号整数类型范围的公共部分应具有相同的表示(根据脚注31,“可互换性作为函数的参数”)。因此,%d表达式的结果是如上所述的无符号a - b,除非我遗漏了某些内容,否则使用1001说明符打印此特定无符号值是合法的,因为它会丢失在%d的正范围内。使用int打印(unsigned) INT_MAX + 1将是未定义的,但%d没问题。

答案 1 :(得分:14)

int为32位的典型实现中,转换为unsigned int时的-1为4,294,967,295,确实≥1000。

即使您在unsigned世界中对待减法,1000 - (4,294,967,295) = -4,294,966,295 = 1,001也是如此。

这就是为什么gcc会在unsignedsigned进行比较时发出警告的原因。 (如果没有看到警告,请传递-Wsign-compare标志。)

答案 2 :(得分:0)

您正在进行无符号比较,即比较1000到2 ^ 32 - 1。

由于printf中的%d,输出已签名。

N.B。有时混合有符号和无符号操作数时的行为是特定于编译器的。我认为最好避免它们,并在有疑问时进行演员表。

答案 3 :(得分:0)

找到一种简单的比较方法,当你无法摆脱无符号声明时可能很有用(例如,[NSArray count]),只需将“unsigned int”强制为“int”。

如果我错了,请纠正我。

if (((int)a)>b) {
    ....
}

答案 4 :(得分:0)

硬件旨在将已签名与已签名和无符号进行比较。

如果需要算术结果,请先将无符号值转换为更大的有符号类型。否则,编译器会假设比较实际上是在无符号值之间。

-1表示为1111..1111,因此它的数量非常大......最大的...当被解释为无符号时。

答案 5 :(得分:0)

 #include<stdio.h>
 int main()
 {
   int a = 1000;
   signed int b = -1, c = -2;
   printf("%d",(unsigned int)b);
   printf("%d\n",(unsigned int)c);
   printf("%d\n",(unsigned int)a);

   if(1000>-1){
      printf("\ntrue");
   }
   else 
     printf("\nfalse");
     return 0;
 }

为此,您需要了解运算符的优先级

  1. 关系运算符从左到右工作... 所以它来了

    if(1000> -1)

然后首先它将-1更改为无符号整数,因为int默认情况下被视为无符号数字,并且其范围大于有符号数字

-1将变为无符号数字,它将变为非常大的数字

答案 6 :(得分:-1)

比较a> b(其中a为无符号int类型,b为int类型)时, b类型转换为unsigned int ,因此,有符号int值-1转换为unsigned MAX的最大值** (范围:0至(2 ^ 32)-1)** 因此,a> b,即(1000> 4294967296)变为假。因此,否则执行循环 printf(“ a is SMALL!%d \ n”,a-b);