算术转化和整型提升的奥秘

来源:互联网 发布:淘宝主店怎么绑定分店 编辑:程序博客网 时间:2024/05/02 02:38

首先请大家先思考一下3个问题,问题相互之间是有关联的。

1,整型字面值是属于整型家族9种中的哪一种呢?

2,什么是算术转换?如何转换的?

3,什么是整型提升?如何提升的?为什么会有整形提升?


下面解答上述问题。

1,整型字面值是属于整型家族9种中的哪一种呢?

答案取决于字面值时如何书写的。比如在整数字面值后面后面添加字符L或l,可以使这个整数被解释为long整型值,字符U或u则用于把数值制定为unsigned整型值。如果在一个字面值后面各添加这两组字符中的一个,那么它就解释为unsigned long整型值。

整型字面值可能int,long或unsigned long。在缺省情况下,它是最短类型但能完整容纳这个值。

例如:在监视中,我们可以明确的看到编译器对于整型字面值在计算时是如何存储的

可以看出即便是再小的数,也会当做是int型,随着整数的增大,整数的类型也会随着变大。直到超出最大范围。


2,什么是算术转换?如何转换的?

算术转化:如果某个操作符的各个操作数属于不通过的类型,那么除非其中一个操作数转换为另外一个操作数的类型,否则操作就无法进行。

下面的层次体系称为寻常算术转换(usual arithmetic conversion)

long double

double

float

unsigned long int

unsigned int

int

vs文档中常用算术转换规定

  1. 如果任一操作数是 long double 类型,则将另一个操作数转换为 long double 类型。

  2. 如果未满足上述条件,并且任一操作数是 double 类型,则将另一个操作数转换为 double 类型。

  3. 如果未满足上述两个条件,并且任一操作数是 float 类型,则将另一个操作数转换为 float 类型。

  4. 如果未满足上述三个条件(所有操作数都不是浮点型),则对操作数执行整型转换,如下所示:

    1. 如果任一操作数是 unsigned long 类型,则将另一个操作数转换为 unsigned long 类型。

    2. 如果未满足上述条件,并且任一操作数是 long 类型且另一个操作数是 unsigned int 类型,则将两个操作数都转换为 unsigned long类型。

    3. 如果未满足上述两个条件,并且任一操作数是 long类型,则将另一个操作数转换为 long 类型。

    4. 如果未满足上述三个条件,并且任一操作数是 unsigned int类型,则将另一个操作数转换为 unsigned int 类型。

    5. 如果未满足上述任何条件,则将两个操作数转换为 int 类型。

换句话说就是:如果某个操作数的类型在上面这个列表中排名较低,那么它首先将转换成另外一个操作数的类型然后执行。


例子:

int a = -1;unsigned int b = 0xffffffff;char c = -1;if (a > b)printf("a > b\n");else if (a == b)printf("a = b\n");elseprintf("a < b\n");if (c > sizeof(c))printf("c > sizeof(c)\n");

输出:


解析:

结果并没有按照我们想的大小来比较,而是发生了我们没有看见的隐式算术转换。

int类型a和unsigned int类型b来操作数'<'、'=='、'>'两边,比较时,其中a发生算术转换暂时变为unsigned int a.而-1的补码和0xffffffff的补码相同,所以两数相同。输出a = b;

同理。sizeof()返回值为size_t类型的1, unsigned int。char c会变为unsigned int c,然后与unsigned int 1比较大小,自然是大于1.


3,什么是整型提升?为什么会有整形提升?如何提升的?

概念:C的整型算术运算总是至少以缺省整数类型的精度(int)来进行的。为了获取这个精度,表达式中的字符型和短整型操作数在使用之前被转化为普通整型,这种转化称为整型提升(integral Promotion)。换句话说,在表达式计算时,各种整型首先要提升为int类型,如果int类型不足以表示则要提升为unsigned int类型,然后进行表达式的运算。

存在原因:通常情况下,在32位平台下,在对int类型的数值做运算时,CPU的运算速度是最快的。C语言是一个注重效率的语言,所以它会做整型提升,使得程序运行速度更快。

提升规则:有符号的在左边补上符号位,无符号的在左边补上0。


想要知道有没有整型提升,关键还是要看汇编

例子:

注意下图中的汇编语句,对比char和int的不同


可以发现,在初始化a,b,aa,bb时,都是用整型字面值赋值。对于a,b来说只是截取了其中一部分。但不影响获得后a,b的内容。

重点:对比 char c = a+b;和int cc = aa+bb;这两行代码的汇编不同;

一个是movsx,一个是mov;

movsx:表示带符号扩展,并传送。

即:在计算c时,a和b进行了符号扩展,b和c的值被提升为普通整型,然后再执行加法运算。加法运算的结果将被截断,然后在存储于c中。



下面给出一个整型提升方面的经典例子。

char c;unsigned char uc;unsigned short us;c = 128;uc = 128;us = c + uc;printf("Ox%x\n", us);us = (unsigned char)c + uc;printf("0x%x\n", us);us = c + (char)uc;printf("0x%x\n", us);

各位可以试着练练手,画画图。然后与答案对比下。







答案:

注意有无符号数字的存储形式。

如何整型提升的



注:算术变换和整形提升的区别:

算术变换主要针对操作符两边操作数类型不同,用来解决类型不匹配问题。

整型提升主要针对操作数是否便于计算,用来解决计算求值问题。


2 0