14.3 类型转换
如果有人问C语法规则中最复杂的是哪一部分,我一定会说是类型转换。从上面两节可以看出,有符号、无符号整数和浮点数加起来有那么多种类型,每两种类型之间都要定义一个转换规则,转换规则的数量自然很庞大,更何况由于各种体系结构对于整数和浮点数的实现很不相同,很多类型转换的情况都是C标准未做明确规定的阴暗角落。虽然我们写代码时不会故意去触碰这些阴暗角落,但有时候会不小心犯错,所以了解一些未明确规定的情况还是有必要的,可以在出错时更容易分析错误原因。本节分成几小节,首先介绍哪些情况下会发生类型转换以及会把什么类型转换成什么类型,然后介绍编译器如何处理这样的类型转换。
14.3.1 Integer Promotion
在一个表达式中,凡是可以使用int或unsigned int类型做右值的地方也都可以使用有符号或无符号的char型、short型和Bit-field。如果原始类型的取值范围都能用int型表示,则其类型被提升为int;如果原始类型的取值范围用int型表示不了,则提升为unsigned int型,这称为Integer Promotion。做Integer Promotion只影响上述几种类型的值,对其他类型无影响。C99规定Integer Promotion适用于以下几种情况:
1.如果一个函数的形参类型未知,例如使用了Old Style C风格的函数声明(详见第3.2节),或者函数的参数列表中有...,那么调用函数时要对相应的实参做Integer Promotion,此外,相应的实参如果是float型的也要被提升为double型,这条规则称为Default Argument Promotion。我们知道printf的参数列表中有...,除了第一个形参之外,其他形参的类型都是未知的,比如有以下代码:
- char ch = 'A';
- printf("%c", ch);
ch要被提升为int型之后再传给printf。
2.算术运算中的类型转换。有符号或无符号的char型、short型和Bit-field在进行算术运算之前首先要做Integer Promotion,然后才能参与计算。例如:
- unsigned char c1 = 255, c2 = 2;
- int n = c1 + c2;
计算表达式c1 + c2的过程其实是先把c1和c2提升为int型然后再相加(unsigned char的取值范围是0~255,完全可以用int表示,所以提升为int就可以了,不需要提升为unsigned int),整个表达式的值也是int型,最后的结果是257。假如没有这个提升的过程,c1 + c2就溢出了,溢出会得到什么结果是Undefined的,在大多数平台上会把进位截掉,得到的结果应该是1。
除了+号之外还有哪些运算符在计算之前需要做Integer Promotion呢?我们在下一小节先介绍Usual Arithmetic Conversion规则,然后再解答这个问题。