编译器如何处理类型转换
在两种类型之间做转换,转换结果将取决于两种类型的精度:
1. 精度是N的有符号整数类型应该用N个Bit表示,取值范围至少应该覆盖(-2N-1, 2N-1)。例如signed char型用8个Bit表示,表示的取值范围是[-128, 127],也可以说是覆盖了(-128, 128),所以这种类型的精度是8。
2. 精度是N的无符号整数类型应该用N个Bit表示,取值范围是[0, 2N-1]。
3. 精度是N的浮点数类型的取值范围至少应该覆盖(-2N-1, 2N-1)的整数值。
现在要把一个精度是M的类型(值为X)转换成一个精度是N的类型,所有可能的情况如下表所示:
待转换的类型 |
N < M的情况 |
N == M的情况 |
N > M的情况 |
signed integer to signed integer |
discard m.s. M-N bits (can overflow) |
same value |
same value |
unsigned integer to signed integer |
if (X < 2N-1) same value else impl.-def.(can overflow) |
if (X < 2N-1) same value else impl.-def.(can overflow) |
same value |
floating-point to signed integer |
if (|X| < 2N-1) trunc(X) else imple.-def. (can overflow) |
if (|X| < 2N-1) trunc(X) else imple.-def. (can overflow) |
if (|X| < 2N-1) trunc(X) else imple.-def. (can overflow) |
signed integer to unsigned integer |
if (0 <= X) X % 2N else impl.-def. |
if (0 <= X) same value else X + 2N |
if (0 <= X) same value else X + 2N |
unsigned integer to unsigned integer |
X % 2N |
same value |
same value |
floating-point to unsigned integer |
if (0 <= X < 2N) trunc(X) else imple.-def. (can overflow) |
if (0 <= X < 2N) trunc(X) else imple.-def. (can overflow) |
if (0 <= X < 2N) trunc(X) else imple.-def. (can overflow) |
signed integer to floating-point |
keep sign, keep m.s.N-1 bits |
same value |
same value |
unsigned integer to floating-point |
+ sign, keep m.s. N-1 bits |
+ sign, keep m.s. N-1 bits |
same value |
floating-point to floating point |
keep m.s. N-1 bits (can overflow) |
same value |
same value
|
上表中的一些缩写说明如下:
impl.-def.表示Implementation-defined;
m.s. bit表示MostSignificant Bit;
trunc(X)表示取X的整数部分,即Truncate Toward Zero;
X % Y就是取模
用法:
float型转short型,对应表中的floating-point to signed integer一行,可以看到,不管两种类型的精度如何,处理方式是一样的,如果float类型的值在(-32768.0, 32768.0)之间,则截掉小数部分就可以了,如果float类型的值超出了这个范围,则转换结果是未明确定义的,有可能会产生溢出,例如对于short s =32768.4。
把int类型转换成unsigned short类型,对应表中的unsigned integer to unsigned integer一行,如果int类型的值是正的,则把它除以216取模,其实就是取它的低16位,如果int类型的值是负的,则转换结果是未明确定义的。
把int类型转换成short类型,对应表中的第一行signed integer to signed integer,把int类型值的高16位丢掉(这里的m.s.包括符号位在内,上表中另外几处提到的m.s.应该是不算符号位在内),只留低16位,这种情况也有可能溢出,例如对于short s = -32769。
把short型转换成int型,仍然对应表中第一行,转换之后应该是same value。那怎么维持值不变呢?是不是在高位补16个0就行了呢?如果short型的值是-1,按补码表示就是十六进制ffff,要转成int型的-1需要变成ffffffff,因此需要在高位补16个1而不是16个0。换句话说,要维持值不变,在高位补1还是补0取决于原来的符号位,这称为符号扩展(Sign Extension)。