一、类型转换
当一个运算符的几个操作数类型不同时,就需要通过一些规则把它们转换为某种共同的类型。
- 一般来说,自动转换是指把“比较窄的”的操作数转换为“比较宽的”的操作数,并且不丢失信息的转换。例如:
float f = 1.2;
int i = 2;
float g = f + i;
printf("%f", g);
- 不允许使用无意义的表达式,例如,不允许把float类型的表达式作为下标
- 针对可能导致信息丢失的表达式,编译器可能会给出警告信息,比如把较长的整型值赋给较短的整型变量,把浮点型值赋值给整型变量,等等,但这些表达式并不非法。
float f = 1.2;
int i = f;
printf("%d\n", i);
i = 128;
char j = i;
printf("%d\n", j);
- 将字符类型转换为整型时,我们需要注意一点:C语言中没有指定char类型的变量是无符号还是带符号变量。所以,当把一个char类型的变量转换为int类型的值时,其结果有没有可能是负整数呢?答案是不一定,取决于具体的机器实现。在某些机器中,如果char类型的最左一位为1,则转换为负整数(符号扩展);而在另一些机器中,char类型左边添加0,则转换为正整数。
- C语言的定义保证了机器的标准打印字符集中的字符不会是负值,因此,在表达式中,这些字符总是正值。但是,存储在字符变量中的位模式在某些机器中可能是负的。所以,为了保证程序的可移植性,如果要在char类型的变量中存储非字符数据,最好指定signed或unsigned限定符。
unsigned char c = 2;
int i = c;
printf("%d\n", i);
- 隐式类型转换规则
- 二元运算符的两个操作数类型不同
- 没有unsigned操作数
- 如果其中一个操作数的类型为long double,则将另一个操作数转换为long double类型
- 如果其中一个操作数的类型为double,则将另一个操作数转换为double类型(注意:float不会自动转换为double)
- 如果其中一个操作数的类型为float,则将另一个操作数转换为float类型
- 将char类型和short类型转换为int类型
- 如果其中一个操作数的类型为long,则将另一个操作数转换为long类型
- 有unsigned操作数时,转换规则要复杂一些,主要原因在于,带符号值与无符号值之间的比较运算是与机器相关的,因为它们取决于机器中不同整数类型的大小。例如:假定int类型占16位,long类型占32位,那么,-1L<1U,这是因为unsigned int类型的1U将被提升为signed long类型;但-1L > 1UL,这是因为-1L将被提升为unsigned long类型,因而成为一个比较大的正数。
- 赋值时,赋值运算符右边的值需要转换为左边变量的类型。
- 字符型变量都将被转为整型变量
- 当把较长的整数转为较短的整数或char类型时,超出的高位部分将被丢弃。
- float转换为int类型时,小数部分将被截取掉
- double转换为float类型时,是四舍五入还是截取,取决于具体的实现
- 由于函数调用的参数是表达式,所以把参数传递给函数时也可能进行类型转换。在没有函数原型的情况下,char与short类型将被转换为int类型,float类型将被转换为double类型。因此,即使调用函数的参数为char或float类型,我们也把函数参数声明为int或double类型。
- 显式类型转换规则
- 在任何表达式中,都可以使用一个称为强制类型转换的一元运算符强制进行显式类型转换。其形式如:
(类型名) 表达式
在上述语句中,表达式首先被赋值给类型名指定的类型的某个变量,然后再用该变量替换上述整条语句。最终结果就是上述表达式被转换为类型名指定的类型,例如库函数sqrt(double),如果给sqrt函数传入一个整数n,可以用 sqrt((double) n),在把n传递给函数之前先将其强制转换为double类型。(注意:强制类型转换只是生成一个指定类型的n的值,n本身并没有改变)
- 在通常情况下,参数是通过函数原型声明的,这样,当函数被调用时,声明将对参数进行自动强制转换。例如,对于sqrt的函数原型:double sqrt(double); 下列函数调用:
root = sqrt(2);
不需要使用强制转换运算符就可以自动将整数2强制转换为double类型的值2.0