最近看到一段代码,如下:
int main(void)
{
unsigned int a = 6;
int b = -20;
int c = (a+b>0)? 1 : 0;
printf("%d\n",a+b);
printf("%d\n",c);
return 0;
}
看到这里就有点好奇了,a+b打印出来明明是-14,表达式为假,C怎么还是1呢?
这里就涉及到C语言的一个隐式转换和数据在机器里面存放的形式。
注:如果带符号类型的值域包含了无符号类型所表示的值,就把无符号类型转化为有符号类型。否则两个操作数都转化为对应的无符号类型。
很显然,带符号的值域int 没有包含住unsigned int的值域。所以a+b都将转化为unsigned int类型。
这里有个需要了解的小知识点,计算器是怎么分辨无符号还是有符号数据的?
https://blog.csdn.net/qq_40627648/article/details/84348233
上面这篇文章讲的很详细。也就是在硬件层面是没有有符号和无符号之分的。
数据的运算都是采用补码来计算。(死去的数电开始攻击我。。。)
unsigned int a = 6; 无符号数据(也就是正数)的原码、反码、补码都相同
00····0000 0110 (32位)
int b = -20
原码:10····0001 0100(32位,后面都是)
反码:符号位不变(原码的首位位符号位),其他位取反
10····1110 1011
补码:反码+1
11····1110 1100(省略号全是1)
a+b 为补码相加:00····0000 0110 + 11····1110 1100 = 11····1111 0010(补码,省略号全为1)
也就是a+b的结构存放的是形式为:上面的补码,我们转为原码看看是不是-14;
11····1111 0010 ------> (取反)10···· 0000 1101 ---------> (+1)10···· 0000 1110 -------> -14
到此为此,我们再回头看看上面代码,a+b为unsigned int类型相加,结果也为unsigned int类型。
上面说的,机器并不知道11····1111 0010这个是有符号数还是无符号数。
而a+b返回的肯定是unsigned int类型。所以默认读出来是一个无符号数,11···1111 0010 对应的无符号数是 4294967282
所以表达式为真,结果为1.
printf("%d")打印出来默认为有符号的。如果采用printf("%u")形式打印,则结果为4294967282
以上做一个记录。
还有个比较容易犯错的地方。sizeof的返回值为unsigned类型。切记直接和int类型的负数相加!!!!