类型转换
隐式转化
不需要人为参与而产生的默认转称为隐式转化。
隐式转化,是计算机语言实现层面最难的,指针是使用层面最难的。
当下,我们只是了解的一些规则,不考虑溢出,截断和有无符号。
后面博客会有更为详细的说明。
隐式转换规则:
算数转换
整型提升
char short int 等类型在参与运算时,首先提升到 int,这种现象叫作整型提升。
整型提升的原理是符号扩充。
例如: 不同的整型类型数据相加。
char + char
char + char
char + int
char + short
short + int
我们用代码加以解释:
#include <stdio.h>
itn main()
{
char ch = 1;
short sh = 1;
int in = 1;
printf("sizeof(ch) = %d\n", sizeof(ch));
//不涉及计算 ch是一个字节
printf("sizeof(ch + ch) = %d\n", sizeof(ch + ch));
//涉及计算 ch为4个字节
//所以体现出来 char类型在参与计算的时候提升到int类型
printf("sizeof(sh) = %d\n", sizeof(sh));
//不涉及计算 ch是一个字节
printf("sizeof(sh + ch) = %d\n", sizeof(sh + ch));
//涉及计算 ch为4个字节
printf("sizeof(in) = %d\n", sizeof(in));
//不涉及计算 ch是一个字节
printf("sizeof(in + ch) = %d\n", sizeof(in + ch));
//涉及计算 ch为4个字节
return 0;
}
输出结果为:
给出两种不同的整型的变量,得到计算之后的结果所占字节的大小,就可以得到不同的整型在计算的过程中转化之后的类型。
上面的方法也就是用sizeof(两个不同的整型进行计算)来得到整型提升之后的类型
(上面这种方法用于验证及其重要)
整型提升原理:符号扩充
#include <stdio.h>
int main()
{
char ch ;
int in;
ch = -1;
in = ch;
printf("ch = %d\n", ch);
printf("in = %d\n", in);
//涉及符号扩充
return 0;
}
运行结果为:
符号扩充
小空间到大空间由于符号扩充的行为,符号保持不变
小数据赋值给大变量 符号不丢失
大数据赋值给小变量 有可能会溢出导致数据丢失
#include <stdio.h>
int main()
{
char ch;
int in;
ch = 127;
in = ch;
printf("ch = %d\n", ch);
printf("in = %d\n", in);
return 0;
}
输出结果为:
以上结果我们给出图解:
我们在这里主要注意有符号和无符号的整型数据在类型转换时候的区别,上图红色部分表示数字-1从char类型进入到int类型的过程,黑色部分表示数字127从char类型进入到int类型的过程,我们在char类型里面用物理存储方式保存之后,只需要在int类型里面保证符号为不改变。
以上给出的分析图需要读者深刻理解,在这里再强调,存储数据的时候是数据的补码存储,符号位是通过补码的第一位来判断,例如char类型的127物理存储第一位是0 那么进入int类型存储的过程中首位符号位也必须是0来保证char类型进入到int类型之后的符号为不变。-1同理也要保证符号位不变,从而来保证数据的准确性。
整型提升,小范围向大范围空间转化,由于符号扩充的存在,保证数据的正确性。
大变量赋值给小数据有可能就会发生数据丢失。取决于赋值之后是否溢出。
混合提升
前面我们介绍的都是整型的类型提升,那么如果是int float double longlong 等类型在一起运算呢?
我们首先给出不同类型所占的大小,然后用一种巧妙的方式得出以上类型在计算的时候类型的提升转换。
不同的大小字节是否一定是小字节转化为大字节呢?
我们接下来进行说明
int类型和float类型计算时,int 向 float类型转化
**int类型和double类型计算时,int 向 double转化 **
float类型和double类型计算时,float类型向double类型转化
我们经过验证
float 类型和 long long类型进行计算的时候 long long 类型会转换为float类型
long long类型和 double类型进行计算的时候 long long 类型会转换为double类型
以下给出代码并且进行解释:
#include <stdio.h>
int main()
{
printf("%d\n", sizeof(long long));
printf("%d\n", sizeof(double));
printf("%d\n", sizeof(int));
printf("%d\n", sizeof(float));
float f = 3.4;
long long i = 5;
//类型不匹配的时候输出结果是错误的 ********* 方法
printf("f + i = %d\n", f + i);
printf("f + i = %f\n", f + i);
return 0;
}
输出结果为:
由于float +long long 的3.4 和 5 最终结果以%f格式打印出来正确结果,所以float类型和long long类型进行计算的时候转换为float类型。
我们每一个混合提升不同类型的计算都使用这种方法,只是修改类型,用参与运算的两种类型分别输出,如果类型匹配输出正确,那么就是转化之后提升的类型,输出不正确,所输出的格式类型就是两种格式在计算的时候转换提升的类型。
所有的混合提升都可以使用这种方法进行检验。我们在前面已经给出了结论,其他的类型读者可以自行检验。
使用的要点就是:类型不匹配的时候运行结果是错误的。
赋值转换
整型和实型之间是可以相互赋值的。赋值的原则是,一个是加零,一个是去小数位。
#include <stdio.h>
int main()
{
int in = 10; //整数向小数赋值 加小数点
float fl = 3.14;//小数向整数赋值去除小数 整数部分赋值
fl = in;
printf("%f", fl);
return 0;
}
输出结果为:
整数向小数赋值 加小数点
#include <stdio.h>
int main()
{
int in = 10; //整数向小数赋值 加小数点
float fl = 3.14;//小数向整数赋值去除小数 只有整数部分赋值
in = fl;
printf("%d", in);
return0;
}
输出结果为:
带有小数点的数向整数赋值去除小数点及其之后的数 只有整数部分赋值
强制转换
隐式类型转化,是有缺陷的,当隐式类型转化不能满足我们的需求时,就需要强制类型转化。
格式:
(类型) 待转表达式
#include <stdio.h>
int main()
{
int a = 10;
int b = 3;
printf("%d\n", a / b);
printf("%f\n",(float)a / b);
printf("%f",10 / 3.0);
return 0;
}
输出结果为:
大多数情况下使用强制类型转化的原因是程序设计的不够好,是对于设计缺陷的一种补救
编译器使用注意
最后我们说明一点小问题:本篇文章在使用scanf函数时使用了scanf_s 其实两个是一样的,只不过vs2019改进了scanf的一些安全问题,这种写法来自与编译器,读者在编写代码的时候只需要使用scanf即可,效果完全相同,如果读者也使用的是vs2019并且也想要使用scanf而不是用scanf_s需要宏定义:
#define _CRT_SRCURE_NO_WARNINGS
就可以解决。
小结
在前面我们用大量时间和内容说明一些底层知识是很有必要的,这对于我们之后的整个学习过程和理解都有很大的作用,对于我们理解数据类型和操作,在真正认识类型的基础上去使用和操作,才能把类型用的更加准确和减少我们的一些错误的发生,所以我认为是很有必要的。