隐式类型转换

C语言中有以下四种情况会进行隐式转换:
1、算术运算符中,低类型转换为高类型。
2、赋值表达式中,右边表达式的值自动隐式转换为左边变量的类型,并赋值。
3、函数调用传递参数时,系统将实参转换为形参的类型后,赋给形参。
4、函数有返回值是,系统将表达值类型转换为返回值类型。

1、算术转换

进行算术运算时,不同类型的数必须转换成同一类型的数据才能进行运算,在转换时依照低级类型向高级类型转换,其转换类型高低级如图所示:
这里写图片描述
在运算的时候,以表达式中最长类型为主,其他类型均往该类型转换,如:
(1)如果运算中有double或者float型的,则其他的类型均转换成double类型进行运算;
(2)如果运算中最长类型为int,那么char也将转换为int进行运算。
PS:算术转换是在运算过程中自动完成的;

包含long与unsigned int,在32位环境中都是4字节,所以均转换为unsigned long。
包含signed int和unsigned int,signed会转换为unsigned,如果int恰好为负数,那么在运算时通过取补码相加的方式运算,结果可能就是一个很大的数了,现在我们通过以下两个代码来给大家讲一下:

1.1 当转换类型所占字节小于原类型

(1)如果int为正数,与无符号进行运算,直接取所需位数的原码即可。例如:

#include<stdio.h>
#include<stdlib.h>

int main(){
    int a = 300;
    int b = -1;
    unsigned char c = a;
    printf("%d\n", c);
    c = b;
    printf("%d\n", c);

    return 0;
}

该程序的运行结果为44、255,说到这里,可能就觉得有些迷惑了,这是为什么?那么我们用两个图来大家说明一下:
这里写图片描述
从图上可以看出,int占位比char多,所以取后8位(因为char占8位),输出来就是44,其实就是a(300)对256取模后的值。
(2)如果int为负数,则先取int的补码,再进行上述计算,例如上面代码中的b,如图所示:
这里写图片描述
如图所示,取-1的补码,然后和(1)中一样,所以输出值为255

1.2 当转换类型所占字节大于等于当前类型

很明显,当大于或等于时,无需截取某一段,直接进行运算就可以,但是同样的,对负数来说,也是要先取补码,再运算,比如下面代码:

#include<stdio.h>

int main(){
    int a = -3;
    unsigned int b = 2;
    long c = a + b;
    printf("%ld\n", c);

    return 0;
}

这段代码在32位环境中运行结果为-1,64位环境中运行结果为4294967295
至于说为什么,也是和上面的一样,-3是一个很小的值,但是当与unsigned类型进行运算的时候,-3先取补码,我们就可以发现,其补码为1111….11100,就成为了一个很大的数,再与2运算,结果就是2^32-1,是一个很大的数,超出了long的最大范围,所以显示为-1,至于4294967295,就是这个真正的值了。
说到这里,就要将将,我们怎么解决这个问题呢?因为我们知道虽然int、long、unsigned int都是4字节大小,但是int和long真正的存储数据的只有31位,第一位是符号位,导致其范围为2^31-1,而unsigned int没有符号位。
第一种方法:printf(“%lu\n”, a + b);即可输出正常的值;
第二种方法:定义c为long long,用%lld输出也可以,因为long long占8个字节,完全可以放得下。

PS:即使操作数中只有char、short,也是先转换为int进行计算

2、赋值转换

在赋值时,赋值运算符右边的类型必须转换为左边的类型,如果右边的类型长度大于左边,则要进行截取的操作。
以以下例子做说明:

int main(){
    char a = 2;
    int i = 257;
    a = i;
    printf("%d\n", a);

    return 0;
}

因为char的范围为0-255,且 i 的长度是大于char的,所以在赋值后,会对 i 进行截取,所以最后输出结果就是1,也很容易计算,当 i>255,则对256取模就是最后的结果。

3、输出转换

在使用printf按制定格式输出的时候,当输出的类型和输出格式不符合的时候,就会进行类型转换。例如:用long输出%d,则相当于将long转换为int输出;将int用%c输出,相当于将int转换为char再输出。用以下两个例子说明:

int main(){
    int a = 65;
    int b = 321;
    printf("%c\n", a);
    printf("%c\n", b);

    return 0;
}

根据前文解释,此处输出应为两个‘A’;
我们再看下一个例子:

int main(){
    long a = 80000;
    long b = 32769;
    printf("%hd\n", a);
    printf("%hd\n", b);
    //1000 0000 0000 0001     32769的原码
    //1 0011 1000 1000 0000     80000的原码
    //11 1000 1000 0000   14464的原码
    return 0;
}

答案是14464 -32767,为什么和上一个直接取模不一样呢?那是因为char是无符号的,而%hd(short)是有符号的,所以:
在取80000时,看注释,取后面16位,首位为0,是正数,直接就是结果:14464;
而取32769的时候,首位为1,是负数,所以取其补码,结果就是-32767。
其实我们也可以从取模的角度来思考,当超过32767,由于short的取值范围是 -32767—32767,所以,又从负数开始取到正数,再如此循环,因此我们会看到当long的值不断增大,输出结果呈现的是正负不断交替的。

4、函数返回值隐式转换

相信看了前面的,大家肯定也明白了这是怎么一回事,这里就不再赘述了,直接通过这段代码来展示一下:

int fun(double n){
    return n;
}

int main(){
    double a = 5.69;
    printf("%d\n", fun(a));
    return 0;
}

结果当然就是5啦,其他的比如int到short,负数的结果什么的,就交给大家自己去实验了,只要明白了他的原理,无论何时都够很轻易地分析出来的。最后,给一张汇总图了断,哈哈哈哈哈
这里写图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值