题
请参阅此代码片段
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 很小: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
分支,这是你在实验中观察到的东西。
在相同的转换规则适用于减法。你a-b
真的解释为a - (unsigned) b
和结果类型unsigned int
。这样的值不能被打印与%d
格式说明中,由于仅%d
与签名值的工作原理。你尝试与未定义的行为%d
结果打印出来,这样就看到印刷(即使它具有在实践中的逻辑确定性解释)的值是从图的C语言的点完全没有意义的。
编辑:其实,我可能是错关于未定义行为的一部分。据C语言规范的范围内的公共部分相应的有符号和无符号整数类型应具有相同的表示(这意味着,根据本脚注31,“互换性作为函数的参数”)。所以,a - b
表达式的结果是如上文所述的无符号1001
,除非我失去了一些东西,它是合法的打印与%d
符这个特定的无符号的价值,因为它属于int
的正面范围内。与(unsigned) INT_MAX + 1
印刷%d
将是不确定的,但1001u
是细
其他提示
在一个典型的实现方式,其中int
是32位,-1时转换为unsigned int
是4294967295这的确是≥1000
即使你把在unsigned
世界减法,1000 - (4,294,967,295) = -4,294,966,295 = 1,001
这是你会得到什么。
这就是为什么当你与gcc
比较unsigned
signed
会吐出警告。 (如果您没有看到一个警告,通过-Wsign-compare
标志。)
您正在做无符号比较,即比较1000〜2 ^ 32 - 1
的输出,因为在printf的%d的签名。
N.B。有时当你混合签署的行为和无符号操作数是编译器特定的。我认为这是最好的,以避免他们做蒙上有疑问时。
找到一个简单的方法来比较,也许有用,当你无法摆脱无符号的声明,(例如,[NSArray的计数]),只是迫使“无符号整型”到“INT”。
如果我错了,请大家指正。
if (((int)a)>b) {
....
}
硬件设计来比较签名到符号和无符号无符号。
如果你想要的运算结果,第一个无符号值转换为一个更大符号的类型。否则编译器港岛线假定比较确实是无符号的值之间。
和-1表示为1111..1111,所以这是一个非常大的数量...最大的...当解释为无符号。
#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;
}
为此,您需要了解运算符的优先级
关系运算符从左到右工作...所以当它到来时
如果(1000>-1)
那么首先它会将 -1 更改为无符号整数,因为 int 默认情况下被视为无符号数,并且它的范围大于有符号数
-1会变成无符号数,变成很大的数
当比较A> B,其中a是无符号整型类型和b是整数类型,的 b的键入浇铸无符号整型强>所以,符号int值-1转换成无符号的MAX值** (范围:0到(2 ^ 32)-1)** 因此,A> B,即(1000> 4294967296)变为假。因此其他环的的printf( “a是SMALL%D \ N!”,A-B); 强>执行