C语言支持基础类型的互相转换,包括自动类型转换和强制类型转换。
对于基础类型的转换,如果未声明转换类型,会自动进行自动类型转换。而如果声明了转换类型,则会进行强制类型转换。例如char类型可以直接赋值给int类型,这就是自动类型转换。自动类型转换方便快捷,但是其隐藏的机制十分复杂,稍不注意就会导致数据精度降低、高位丢失等问题,在编写代码时需要特别注意。
自动类型转换
对于自动类型转换,主要发生在表达式中,例如算术表达式(+,-,*,/,%),赋值表达式(=)中,下面分别进行说什么。
运算表达式中的类型转换
算术表达式一般是一个或者多个变量进行算术运算,在大部分情况下,都会使用相同的数据类型进行运算,不过在某些情况下,也会发生不同数据类型的运算。
具体示例如下所示。
#include int main(int argc, char *argv[]) { int a = 10; short b = 20; // short类型向int类型转换 int c = a + b; float f1 = 1.0f; // int类型向float类型转换 float f2 = a + f1; unsigned char d = 10; // unsigned char类型向int类型转换 int e = a + d; printf("%d, %d, %d\n", a, b, c); printf("%f, %f\n", f1, f2); printf("%d, %d\n", d, e); return 0; }对于上述代码,具体执行结果如下所示。
在上述语句中,a和b都是int类型,但因为f1是float类型,最终a+f1的结果也是float类型。这里面就涉及到类型的优先级,主要规则如下所示。
这里还有一个隐藏的知识点,如果浮点数声明末尾不带f,会默认存储为double类型,只有带f才会
对于运算表达式中的类型转换,默认情况下都是低级别类型向高级别类型转换,例如int向float转换,long向double转换等。占用空间更大,被称为类型升级,大部分情况下不关注也不会出现问题。
赋值表达式和函数传参中的类型转换
赋值表达式和函数传参中的类型转换则与运算不同,主要是将基本数据类型变量赋值给其它类型变量,具体示例如下所示。
#include void func(unsigned char val) { if (val > 100) { printf("over 100, val:%d\n", val); } else { printf("below 100, val:%d\n", val); // below 100, val:99 } } int main(int argc, char *argv[]) { // 浮点型赋值给int类型 int v1 = 355.5; // int类型赋值给unsigned char类型 unsigned char v2 = v1; long long v3 = v1; printf("v1 = %d\n", v1); // v1 = 355 printf("v2 = %d\n", v2); // v2 = 99 printf("v3 = %lld\n", v3); // v3 = 355 // 将int类型传递到unsiged char类型 func(v2); return 0; }对于上述代码,具体执行结果如下所示。
可以看到,在赋值表达式中,既可以把低级别类型赋值给高级别类型(int赋值给long long类型), 也可以把高级别类型赋值给低级别类型(如float赋值给int类型,int赋值给unsigned char类型)。
对于类型升级,其值仍然保持不变,只是类型被提升。而类型降级时,对于float转int类型,则会丢弃小数部分,只保留整数部分。而int转unsigned char类型时,如果int值大于unsigned char类型的最大值,会发生截断,只保留低8位,这就直接造成了值的变化;这种操作都是自动的,很可能在不知晓的情况发生。
函数的参数作为后续执行的判断条件,那么自动类型转换后,直接改变了参数值,执行了非预期的代码,这在某些情况下会造成严重的结果,因此需要特别注意。