4.11.1 算术转换
算术转换(arithmetic conversion)的含义是把一种算术类型转换成另外一种算术类型,这一点在2.1.2节(第35页)中已有介绍。算术转换的规则定义了一套类型转换的层次,其中运算符的运算对象将转换成最宽的类型。例如,如果一个运算对象的类型是long double,那么不论另外一个运算对象的类型是什么都会转换成long double。还有一种更普遍的情况,当表达式中既有浮点类型也有整数类型时,整数值将转换成相应的浮点类型。
整型提升
整型提升(integral promotion)负责把小整数类型转换成较大的整数类型。对于bool、char、signed char、unsigned char、short和unsigned short等类型来说,只要它们所有可能的值都能存在int里,它们就会提升成int类型;否则,提升成unsigned int类型。就如我们所熟知的,布尔值false提升成0、true提升成1。
较大的char类型(wchar_t、char16_t、char32_t)提升成int、unsigned int、long、unsigned long、long long和unsigned long long中最小的一种类型,前提是转换后的类型要能容纳原类型所有可能的值。
无符号类型的运算对象
如果某个运算符的运算对象类型不一致,这些运算对象将转换成同一种类型。但是如果某个运算对象的类型是无符号类型,那么转换的结果就要依赖于机器中各个整数类型的相对大小了。
像往常一样,首先执行整型提升。如果结果的类型匹配,无须进行进一步的转换。如果两个(提升后的)运算对象的类型要么都是带符号的、要么都是无符号的,则小类型的运算对象转换成较大的类型。
如果一个运算对象是无符号类型、另外一个运算对象是带符号类型,而且其中的无符号类型不小于带符号类型,那么带符号的运算对象转换成无符号的。例如,假设两个类型分别是unsigned int和int,则int类型的运算对象转换成unsigned int类型。需要注意的是,如果int型的值恰好为负值,其结果将以2.1.2节(第35页)介绍的方法转换,并带来该节描述的所有副作用。
剩下的一种情况是带符号类型大于无符号类型,此时转换的结果依赖于机器。如果无符号类型的所有值都能存在该带符号类型中,则无符号类型的运算对象转换成带符号类型。如果不能,那么带符号类型的运算对象转换成无符号类型。例如,如果两个运算对象的类型分别是long和unsigned int,并且int和long的大小相同,则long类型的运算对象转换成unsigned int类型;如果long类型占用的空间比int更多,则unsigned int类型的运算对象转换成long类型。
理解算术转换
要想理解算术转换,办法之一就是研究大量的例子:
- bool flag; char cval;
- short sval; unsignedshort usval;
- int ival; unsigned int uival;
- long lval; unsigned long ulval;
- float fval; double dval;
- 3.14159L + ’a’; // ’a’提升成int,然后该int值转换成long double
- dval + ival; // ival转换成double
- dval + fval; // fval转换成double
- ival = dval; // dval转换成(切除小数部分后)int
- flag = dval; // 如果dval是0,则flag是false,否则flag是true
- cval + fval; // cval提升成int,然后该int值转换成float
- sval + cval; // sval和cval都提升成int
- cval + lval; // cval转换成long
- ival + ulval; // ival转换成unsigned long
- usval + ival; // 根据unsigned short和int所占空间的大小进行提升
- uival + lval; // 根据unsigned int和long所占空间的大小进行转换
在第一个加法运算中,小写字母'a'是char型的字符常量,它其实能表示一个数字值(参见2.1.1节,第32页)。到底这个数字值是多少完全依赖于机器上的字符集,在我们的环境中,'a'对应的数字值是97。当把'a'和一个long double类型的数相加时,char类型的值首先提升成int类型,然后int类型的值再转换成long double类型。最终我们把这个转换后的值与那个字面值相加。最后的两个含有无符号类型值的表达式也比较有趣,它们的结果依赖于机器。
4.11.1节练习
练习4.34:根据本节给出的变量定义,说明在下面的表达式中将发生什么样的类型转换:
(a) if (fval) (b) dval = fval + ival; (c) dval + ival * cval;
需要注意每种运算符遵循的是左结合律还是右结合律。
练习4.35:假设有如下的定义,
- char cval; int ival; unsigned int ui;
- float fval; double dval;
请回答在下面的表达式中发生了隐式类型转换吗?如果有,指出来。
(a) cval = 'a' + 3; (b) fval = ui - ival * 1.0;
(c) dval = ui * fval; (d) cval = ival + fval + dval;