C 强制类型转换
强制类型转换是把变量从一种类型转换为另一种数据类型。例如,如果您想存储一个 long 类型的值到一个简单的整型中,您需要把 long 类型强制转换为 int 类型。您可以使用强制类型转换运算符来把值显式地从一种类型转换为另一种类型,如下所示:
(type_name) expression
请看下面的实例,使用强制类型转换运算符把一个整数变量除以另一个整数变量,得到一个浮点数:
实例
#include <stdio.h>
int main()
{
int sum = 17, count = 5;
double mean;
mean = (double) sum / count;
printf("Value of mean : %f\n", mean );
}
当上面的代码被编译和执行时,它会产生下列结果:
Value of mean : 3.400000
这里要注意的是强制类型转换运算符的优先级大于除法,因此 sum 的值首先被转换为 double 型,然后除以 count,得到一个类型为 double 的值。
类型转换可以是隐式的,由编译器自动执行,也可以是显式的,通过使用强制类型转换运算符来指定。在编程时,有需要类型转换的时候都用上强制类型转换运算符,是一种良好的编程习惯。
整数提升
整数提升是指把小于 int 或 unsigned int 的整数类型转换为 int 或 unsigned int 的过程。请看下面的实例,在 int 中添加一个字符:
实例
#include <stdio.h>
int main()
{
int i = 17;
char c = 'c'; /* ascii 值是 99 */
int sum;
sum = i + c;
printf("Value of sum : %d\n", sum );
}
当上面的代码被编译和执行时,它会产生下列结果:
Value of sum : 116
在这里,sum 的值为 116,因为编译器进行了整数提升,在执行实际加法运算时,把 'c' 的值转换为对应的 ascii 值。
常用的算术转换
常用的算术转换是隐式地把值强制转换为相同的类型。编译器首先执行整数提升,如果操作数类型不同,则它们会被转换为下列层次中出现的最高层次的类型:
常用的算术转换不适用于赋值运算符、逻辑运算符 && 和 ||。让我们看看下面的实例来理解这个概念:
实例
#include <stdio.h>
int main()
{
int i = 17;
char c = 'c'; /* ascii 值是 99 */
float sum;
sum = i + c;
printf("Value of sum : %f\n", sum );
}
当上面的代码被编译和执行时,它会产生下列结果:
Value of sum : 116.000000
在这里,c 首先被转换为整数,但是由于最后的值是 float 型的,所以会应用常用的算术转换,编译器会把 i 和 c 转换为浮点型,并把它们相加得到一个浮点数。
甜笋儿
102***1933@qq.com
如果一个运算符两边的运算数类型不同,先要将其转换为相同的类型,即较低类型转换为较高类型,然后再参加运算,转换规则如下图所示。
甜笋儿
102***1933@qq.com
xxxxripxxxx
roc***lyman@163.com
C 语言中 printf 输出 double 和 float 都可以用 %f 占位符 可以混用,而 double 可以额外用 %lf。
而 scanf 输入情况下 double 必须用 %lf,float 必须用 %f 不能混用。
xxxxripxxxx
roc***lyman@163.com
ssl
157***1786@qq.com
为了提高效率,C 语言对于不同的两个类型将直接转换成较高类型计算。
举个例子:对于已经分别被定义且被赋值,类型为 double 和 int 的 a 和 b:
假设如果进行 a + b 运算,那么b将直接被隐式转换为 double 类型,然后再进行运算,不能理解为逐层转换(即不能理解为b先转换为unsigned int类型,再转换为 long => unsigned long => long long => unsigned long long => float => double类型,最后再进行运算)。
p.s: 说到运算,对于 char 和 short 类型,进行运算时将会被隐式转换为 int,看代码:
输出:
这里没讲,顺带补充一下转换规则:
1、float、double、long double 类型赋值给整数类型:直接截断小数
如:
根据转换规则和隐式类型转换规则,输出的结果为:
2、整数类型赋值给浮点数(float、double、long double)类型:补足有效小数位
对上述代码进行修改:
输出:
3、存储长度较短的类型赋值给存储长度较长的类型:补足有效位,其它位补 0
假设有如下定义:
如果执行以下操作:
那么它们在内存以 2 进制格式分别存储为:
4、存储长度较长的类型赋值给存储长度较短的类型:舍弃高位(但保留符号),截断低字节给存储长度较短的类型
假设定义:
进行赋值:
它们在内存以2进制格式分别存储为:
p.s: 此时的 v=494665727。
顺带说明一下,如果变量 “l” 的后 32 个字节都为 1,那么 v 将等于 -1。
5、unsigned类型赋值给非unsigned类型:直接传递数值
注意:如果 unsigned 类型储存的量太大,强制类型转换后可能会出现非 unsigned 类型的值的绝对值不等于 unsigned 类型的值的绝对值的情况。
说到 “unsigned 类型储存的量太大”,顺带说一下,虽然 printf 输出 int 和 unsigned int 时可以混用 %d(或%i)和 %u(或%ui),但还是建议输出 int 类型的时候用 %d(或%i),输出 unsigned int 类型时用 %u(或%ui)(其它类型同理<如%ul等>)
看一个例子:
可是因为隐式类型转换,结果输出为:
出现“-1”的这个输出就是因为“unsigned类型储存的量太大(大于了同类型但非unsigned的类型)”
p.s: 不一定都为 -1,具体要看 unsigned 类型的值的 2 进制
6、非 unsigned 类型赋值给 unsigned 类型:直接传递数值
给个小技巧:如果你想“临时”给一个不知道正负的非 unsigned 类型的变量加上绝对值,可以使用abs函数,但利用(unsigned)(非unsigned类型变量名)可以节省一点内存开销
但是也有弊端:可能会出现 unsigned-unsigned 永远大于 0 的情况(不确定)
最后补充一下,强制类型转换只是临时类型转换,并不影响变量本身储存的值,看如下代码:
输出结果:
ssl
157***1786@qq.com