【C语言】基础数据类型的隐式转换、截断和整型提升(超详细)

前言

你是否在学习C语言时有认真思考过,如果表达式两边的是不同的数据类型的变量参与运算或者一个双目运算符的操作数的数据类型不一样时(就比如int类型的数据和char类型的数据相加),它们究竟会摩擦出怎样的火花,本文就来探讨一下。

让我们化身为名侦探柯南,通过现象所产生的线索,找到这背后的惊天秘密!

哈哈哈

1. 隐式转换

隐式转换,就是指当两个或多个不同数据类型的变量参与运算时,编译器会根据规则自动的将这些变量的数据类型转换为别的数据类型。这个过程我们程序员没有察觉,故有此得名为"隐式转换"。

那这个规则是什么呢?我们接着往下看!!!
哈哈哈

1.1 隐式转换的规则

在讲这个规则之前,不知道有没有读者脑海里有这么一个想法:既然不同的数据类型的变量参与表达式运算时,会发生隐式转换,那不如我直接拍板决定直接让这些数据类型转化为最大的那个数据类型不就可以了,这样就不会有那么多的约束了。

这个方案显然是略有缺陷的。站在性能和空间的角度看,这是一种其浪费时间资源又浪费空间资源的做法。

那C编译器是怎么做的呢?
隐式转换的规则

  1. 低字节的数据类型向高字节的数据类型转换。
    数据类型
    具体规则:取参与表达式运算的最大数据类型作为标准,其他变量的数据类型都往这个标准进行隐式转换。
  • 举例:有一个表达式,a(char类型) + b(int类型),最后变量a最会被转换为int类型;再来一个,a(char类型) + b(int类型)+ c(float类型),最后变量a和b都会被转换为float类型。
  1. 有符号数向无符号数进行转换
    类型
    以上只是举出部分例子。

  2. 整型类型向浮点数类型转换
    当一个表达式同时出现了整数类型的数据和浮点数类型的数据,最终整型数据会被隐式转换为浮点数类型的数据。这个规则其实就是规则1的情况之一,因为这个规则较为常见所以拿出来单独讲。

2. 截断

当高字节大小的数据向低字节大小的数据赋值时,就会发生截断现象。

2.1 整型家族的截断

整型家族包括:char、short、int、long 、long long…
整型截断的规则:直接将高位数据丢弃,将剩余的低位的数据直接赋值到变量中。

具体操作流程如下:

//在32位的平台上
int main()
{
	char a = 128;
	//其中,a是字符类型,常数128是整型,这里就会发生截断
	//128的原码:00000000 00000000 00000000 10000000
	//128的反码:00000000 00000000 00000000 10000000
	//128的补码:00000000 00000000 00000000 10000000
	//发生截断,也就是保留最低位的那1个字节(char类型的大小)的数据,就变为
	//10000000(这个就是变量a在内存中存储的数值)

	char b = -128;
	//其中,b是字符类型,常数-128是整型,这里就会发生截断
	//-128的原码:10000000 00000000 00000000 10000000
	//-128的反码:11111111 11111111 11111111 01111111
	//-128的补码:11111111 11111111 11111111 10000000
	//发生截断,也就是保留最低位的那1个字节(char类型的大小)的数据,就变为
	//10000000(这个就是变量b在内存中存储的数值)
}

现在我们就测试一下,到底分析的对不对。
测试

可以看到,两个值都打印了ffffff80,这个是十六进制的表示形式。
我们这里只需要观察最后两个数字即可,因为char类型大小就一个字节。

可以看到是80,转换为二进制就是10000000,这个不正是我们所推测的那样,的确发生了截断,而且截断的规则正如我们所讲的那样。

2.2 浮点数家族的截断

浮点数家族:float、double、long double

规则:大家可以自行的去了解,这个关系到浮点数在内存中的存储。

注意:当double类型的数据赋值给float类型的数据时,如果double类型的数据超过了float类型时,此时截断会发生精度的丢失。

2.3 混合截断

规则:当一个浮点数类型的变量赋值给整数类型的变量时,会直接舍弃掉小数点部分把整数部分直接赋值给整型变量。
啊

3. 整型提升

整型提升仅发生在整型家族里面。(牢记)

在标准C中,都会将变量的数据类型转换为整型才进行运算。而整型提升就发生在表达式的运算。

这个条件好熟悉啊!这不就是隐式转换的发生条件吗?没错,这一般都是一个连锁的现象。

3.1 整型提升的规则

  • 对于有符号的整数来说,发生整型提升时,将符号位的数据填充到提升后多出来的空间中。
  • 对于无符号整数来说,发生整型提升时,将0填充到提升之后多出来的空间。

提升的界限就是int类型。

3.2 整型提升的验证

#include<stdio.h>
int main()
{
	char a = 0x86; //1000 0110(十六进制对应的二进制)
	short b = 0x8600; //1000 0110 0000 0000(十六进制对应的二进制)
	int c = 0x86000000; //10000110 00000000 00000000 00000000(十六进制对应的二进制)
	
	//变量a整型提升之后:11111111 11111111 11111111 10000110
	//0x86:00000000 00000000 00000000 10000110
	//自然不相等
	if (0x86 == a) 
		printf("%c\n",'a');
		
	//变量b整型提升之后:11111111 11111111 10000110 00000000
	//0x8600:00000000 00000000 10000110 00000000
	//自然不相等
	if (0x8600 == b)
		printf("%c\n", 'b');
		
	//变量c不会发生整型提升:10000110 00000000 00000000 00000000
	//0x860000:10000110 00000000 00000000 00000000
	//自然相等
	if (0x86000000 == c)
		printf("%c\n", 'c');

	return 0;
}

答案

3.3 整型提升的例子

#include <stdio.h>
int main()
{
	char a = -128;//(截断)
	//-128的原码:10000000 00000000 00000000 10000000
	//-128的反码:11111111 11111111 11111111 01111111
	//-128的补码:10000000 00000000 00000000 10000000
	//发生截断:10000000(变量a存的值)
	
	//因为这里是要以无符号整型的方式去读取这个数据,因此要发生整型提升
	printf("%u\n", a);//11111111 11111111 11111111 10000000(整型提升)
	return 0;
}

结果

好了,到这里不同数据类型的进行表达式运算时竟然有如此多的细节,不过只要我们牢记这些现象发生的条件和对应的规则,那就不成问题了。

最后给大家总结一下:

现象条件规则
隐式转换当两个不同的数据类型进行表达式的运算时1.低字节的数据类型向高字节的数据类型进行转换;2.有符号数向无符号数进行转换;3.整型向浮点型转换。
截断当高字节的数据类型给低字节的数据类型赋值时1.对于整型之间,直接将高位数据舍弃,剩余的数据赋值给变量;2.对于整型和浮点型的情况,直接将小数点后面的值舍弃,并将整数部分直接赋值给整型变量 。
整型提升基于标准C的特点,参与表达式运算的数据类型,低于int类型大小的数据类型全都先转换为int类型参与运算(仅对整型家族有效)1. 对于有符号的整数,以符号位的数据作为填充提升后多出来空间的数值;2.对于无符号的整数,以0作为填充提升后多出来空间的数值

如果你以后遇到看似两个正常的值参与运算时,结果却不符合你的期望,可以试着玩这个方向进行思考。

本文到此结束了,如果觉得本文写的还不错的话,麻烦给偶点个赞吧!!!
哈哈

评论 73
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值