对无符号和有符号整数进行比较操作
看到这个代码片段
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
这就是你所得到的。
这就是为什么当你比较unsigned
和signed
时, gcc
会吐出一个警告。 (如果看不到警告,则传递-Wsign-compare
标志。)
你正在做无符号比较,即比较1000到2 ^ 32 – 1。
输出由于printf中的%d而被签名。
注意有时混合有符号和无符号操作数时的行为是特定于编译器的。 我认为最好是避免他们,并在有疑问时进行投掷。
找到一个简单的方法来比较,也许有用的时候,你不能摆脱无符号声明,(例如,[NSArray计数]),只是强制“无符号整型”为“int”。
如果我错了,请纠正我。
if (((int)a)>b) { .... }
硬件设计用于比较签名和无符号到无符号。
如果你想算术结果,首先将无符号值转换为更大的带符号类型。 否则,编译器会假定比较实际上是无符号的值。
而-1表示为1111..1111,所以它是一个非常大的数量…最大的…当解释为无符号。