对无符号和有符号整数进行比较操作

看到这个代码片段

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

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

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

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

-1被转换为unsigned int ,结果是最大可能的unsigned int值(与UINT_MAX相同)。 不用说,它将大于你的无符号1000值,这意味着a > b确实是错误的,并且a相对于(unsigned) b确实是小的if在你的代码中应该解析为else分支,这是你在实验中观察到的。

相同的转换规则适用于减法。 你的ab真的被解释为a - (unsigned) b ,结果的类型是unsigned int 。 这样的值不能用%d格式说明符打印,因为%d只能用于有符号的值。 您尝试使用%d打印它会导致未定义的行为,因此从C语言的角度来看,您所看到的打印值(即使它在实践中具有逻辑确定性的解释)也是毫无意义的。

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

int为32位的典型实现中,当转换为unsigned int为-1是4,294,967,295,这实际上是≥1000。

即使你在unsigned世界中处理减法, 1000 - (4,294,967,295) = -4,294,966,295 = 1,001这就是你所得到的。

这就是为什么当你比较unsignedsigned时, gcc会吐出一个警告。 (如果看不到警告,则传递-Wsign-compare标志。)

你正在做无符号比较,即比较1000到2 ^ 32 – 1。

输出由于printf中的%d而被签名。

注意有时混合有符号和无符号操作数时的行为是特定于编译器的。 我认为最好是避免他们,并在有疑问时进行投掷。

找到一个简单的方法来比较,也许有用的时候,你不能摆脱无符号声明,(例如,[NSArray计数]),只是强制“无符号整型”为“int”。

如果我错了,请纠正我。

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

硬件设计用于比较签名和无符号到无符号。

如果你想算术结果,首先将无符号值转换为更大的带符号类型。 否则,编译器会假定比较实际上是无符号的值。

而-1表示为1111..1111,所以它是一个非常大的数量…最大的…当解释为无符号。