问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

C语言基础数据类型的隐式转换、截断和整型提升详解

创作时间:
作者:
@小白创作中心

C语言基础数据类型的隐式转换、截断和整型提升详解

引用
CSDN
1.
https://blog.csdn.net/tianxiawushanu/article/details/141473310

在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作为填充提升后多出来空间的数值

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

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号