To be a better coder
分类: C/C++
2018-10-30 15:51:10
原文地址:“C”中的算数转换 作者:lvyilong316
写在前面:本来因为一个朋友问我为什么可以给unsigned int赋值负数,我打算写一篇关于解释unsigned的文章。但是写的过程中发现有很多地方需要涉及其他的知识点,特别是关于整型提升和算数转换。所以就翻了一下之前看过的书,做了一个总结,感觉自己又学到了不少。由于我不是写教科书,有些用语和描述难免不够准确。另外,由于本人能力有限,有错之处在所难免,希望各位看到此文的朋友如果发现有什么错误请留言指正,或发邮件交流。
(电子邮箱: ——转载请注明出处,lvyilong316
许多操作数类型为算数类型的双目运算符会引发转化,并以类似的方式产生结果类型。他的目的是产生一个普通类型,同时也是运算结果的类型。这个模式称为“寻常算数转换”。
——ANSI C手册
当执行算数运算时,操作数的类型如果不同,就会发生转换。 数据类型一般朝着浮点精度更高、长度更长的方向转换 。整型数如果转换为signed不会丢失信息,就转换为signed,否则就转换为unsigned。 这个称为值保留(value preserving)原则,与K&R C所采用的无符号保留(unsigned preserving)原则不同。
无符号保留:就是当一个无符号类型与int或更小的整形混合使用时结果类型是无符号类型。(忘了这个吧,我们以ANSI C为准)
值保留:结果可能是有符号数,也可能是无符号数,取决于操作数类型的相对大小。
也许你读了上面的解释还不清楚,那么我来给你解释下:、
当两个类型长度不同时,短的类型根据自己是signed还是unsigned进行位扩展,然后按较长的类型解释signed或unsigned(类似类型提升)。有人会问为什么得到这个结论,因为短类型向长类型扩展肯定不会丢失信息,可以按照unsigned解释,而长类型按什么解释取决于他自身,如果长类型本身为unsigned,那解释为signed肯定要丢失信息,所以以长类型为准解释signed或者unsigned。
说明:虽然32位下long和int都是4个字节,但是int要向long转(可以当做long比int长)。
当两个类型相同,signed类型不同时(比如int和unsigned int),按照unsigned解释(即都转为unsigned)。这又是为什么呢?因为两个同为类型相同,unsigned的转为signed肯定要丢失高位信息。
说明:这里不包括char,unsigned char,short,unsigned short,因为这些在一起会发生整形提升(扩展后,解释为signed int)。
当有char、short int或者int型位段(无论signed或unsigned)参与的表达式,先对其进行整型提升,提升后若有int(signed或unsigned)或long等更长的类型,在按照算数转换进行转换。否则直接进行算数转换。(float类似)
(1) int a = -1;
unsigned int b = 1;
printf("%d", a > b);//输出1
分析:算数转换,同类型,都转为unsigned int,再来比较。a转化为无符号数后就是0xFFFFFFFF,肯定大于b
(2) char a = -1;
unsigned char b = 1;
printf("%d", a > b);//输出0
分析:整形提升,参看上一节分析。
(3) int a = -1;
unsigned char b = -1;
printf("%d\n", a < b);//输出是1
分析:类型提升,b扩展为0x000000FF,解释为int为255,当然大于-1了。
(4) char a = -1;
unsigned int b = -1;
printf("%d\n", a == b);//输出1
分析:整形提升+算数转换,首先a为0xFF,按照signed扩展为0xFFFFFFFF,解释为int,之后int和unsigned int比较算数转换为unsigned int解释。a,b都为0xFFFFFFFF对应的无符号int,所以相等。其实将b改为int类型,输出一样为1,以为这时只发生了整形提升,提升后两个0FFFFFFFF都解释为int类型(-1),所以相等。b改为unsigned long long呢?还是输出1,先发生整形提升,a提升为int,在算数转换——a由int扩张为8字节,并解释成unsigned long long(0XFFFFFFFFFFFFFFFF),和b相同。
下面是来自网上的一个总结,其实经过这两节的讨论,基本不需要这样去记了,我们可以简单的概括为:有小整形的先提升,signed不同则转换。
无符号int与有符号int比较大小,转化为无符号int来比较
int类型与非无符号int的类型比较时,非无符号int的类型转化为int来比较
无符号int类型与其他类型如unsigned short,signed short,unsigned char, char 比较时,其他类型一律转化为无符号int类型来比较
非无符号int类型和非int类型如unsigned short,signed short,unsigned char, char 比较时,一律转化为int类型来比较