C语言的显式类型转换和隐式类型转换详细讲解

news2024/11/24 3:18:30

 目录

一、类型转换

1、显式类型转换

2、隐式类型转换

二、算术转换

三、总结


每个编译器都会对表达式做两件事情,一是判断表达式中操作符的优先级和结合性,二是判断表达式中的操作数类型是否一致,如果不一致则需要进行类型转换。第一点在我前面的文章中已经讲解过了,这篇就特意来讲解一下第二点类型转换和算术转换。看看编译器是如何进行操作的。

一、类型转换

首先我们先来学习C语言中的类型转换,为什么要进行类型转换呢?因为C的整型算术运算总是至少以缺省整型类型的精度来进行的。编译器为了实现这个精度,所以会将表达式中操作数小于整型数据类型字节大小的数据转换为普通整型再进行运算,这种方法称为整型提升。如果有时候我们知道表达式中的数据需要进行转换,那我们就可以显示转换,如果有时候我们没有对数据进行显示转换,那么编译器就会隐式的帮我们转换。

所以,类型转换分为两种:显式类型转换和隐式类型转换。

显式类型转换:我们自己使用强制类型转换操作符进行数据类型转换。

隐式类型转换:编译器默认的帮我们转换。

那我们现在再来了解一个概念,编译器为什么要提升精度呢?这个就要从计算机层面进行分析,这是我从网上搜到的资料。

表达式的整型运算要在CPU的相应运算器内执行,也就是在CPU内整型运算器(ALU)。

ALU的操作数的字节长度一般就是int的字节长度(4个字节),同时也是CPU的通用寄存器的长度。

因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。

通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int

,然后才能送入CPU去执行运算。

 了解这些之后,我们就分别来学习一下两种方式的类型转换。

1、显式类型转换

int main()
{
    //显式类型转换
    float a = 10.55f;
    float b = 13.14f;
    float c = (int)a + (int)b;
    printf("%f\n",c);

    return 0;
}

大家看代码执行的结果,为什么两个浮点数相加之后,并且我用浮点数打印结果,却结果是不对的,应该打印正确的结果为23.690000。这是因为我对数据类型进行了显式转换的处理。

起到作用的代码主要是这一行:float c = (int)a + (int)b;首先变量a和变量b是浮点型存储在内存中的,然后我从内存中取出这两个变量的时候,就对他们进行了处理。处理的方式就是(int)a,意思就是把a的值取出来强制转换为int的数据类型,(int)c也是同样的处理,这样操作之后 (int)a + (int)b的结果就为10+13=23。最后再把23赋值给变量c,变量c在用浮点数的形式存储在内存中。所以最后打印出来的是23.000000。

看完这段代码是不是对显式类型转换有了一定的了解。这里提一个小小的建议,在以后写代码的时候,如果你知道自己需要使用什么样的数据类型,就提前定义好数据类型,尽量少在表达式中使用显式类型转换。这样可能会给你的代码带来潜在的危害。C语言标准有这个操作,说明也有它的好处存在,所以大家根据需要决定使用。

2、隐式类型转换

隐式这词见名思意就知道是我们不显式的写类型转换,让编译器根据代码的实际情况,判断要不要进行数据转换。编译器隐式转换的主要方法就是整型提升。

编译器是如何进行整型提升的呢?整形提升是按照变量的数据类型的符号位来提升的。下面给大家画图演示一下。

不管是short类型还是char类型,在表达式中进行运算的时候编译器都会按照图片中的方法进行整型提升。以方便CPU进行计算。

我们再来看一个例子:

    char c = -1;
    printf("%d\n",sizeof(c));
    printf("%d\n", sizeof(+c));
    printf("%d\n", sizeof(-c));

为什么同样用sizeof操作符求变量c的字节大小的时候,结果会不一样呢?这就是因为编译器在运行代码的时候,进行表达运算的时候,表达式中的数据类型有小于int字节大小的数据都会被隐式的整型提升操作。sizeof(+c)、sizeof(-c)中的c都做了表达式运算,所以被整型提升了,最后sizeof求的是int类型的字节数。

总结:显式类型转换就是可以随便转换我们想要的数据类型。而这里的隐式转换只是在表达式中,操作数的数据类型有小于int类型的数据转换为int大小的数据,也就是整型提升。这种只是隐式转换的一种形式,还有另外一种形式。

二、算术转换

这里的算术转换其实就是上面所说的隐式转换的第二种形式。这里的算术转换的都是大于等于int类型的数据。算术转换就是在一个表达式中,有两个不同数据类型的操作数,那么编译器就会隐式的转换为一种数据类型,然后进行运算。那编译器是如何判断将两种不同的数据类型转换成一个呢?那请看下面。

long double
double
float
unsigned long int
long int
unsigned int
int

编译器在隐式转换类型的依据就是把精度低的数据类型转换成精度高的数据类型。上面图片就是各种数据类型的精度排行,从下往上就是代表精度从低到高。

    int a = 20;
    float b = 5.23f;
    int c = a + b;

上面的代码中,有两个不同的数据类型变量,在进行   int c = a + b; 表达式运算的时候,会有一个隐式转换的过程。因为int 类型比 float类型的精度低,所以编译器会先把变量a隐式转换为float类型的数据,然后再把两个float类型的a和b进行相加。

注意:虽然编译器会帮我们隐式转换数据类型,提高数据类型精度。但我们还是要合理使用它。比如下面的代码就会带来潜在的问题。

本来我们想要把变量f的值给变量num,但是这里会有一个隐式转换,会把float类型隐式转换为int类型,这样就会导致数据的精度丢失。所以我们要合理的使用它,这种潜在的问题在调试bug的时候不容易找出来。

三、总结

 这节主要讲了类型转换的操作,类型转换主要分为显式类型转换和隐式类型转换。隐式类型转换又分为整型提升和算术转换两个操作。整型提升的用途主要是在表达式中,有数据类型小于int类型大小的,编译器就会隐式的把小于int类型的数据转换为int类型的数据。算术转换的用途就是在表达式中,操作数的数据类型都是大于等于int 类型,并且数据类型不一致,这个时候编译器就会隐式算术转换。两种隐式转换都有一定的潜在问题,大家都要合理使用。

谢谢大家~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1581003.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

R-Tree的简单介绍

一、R-Tree简介 R-Tree,全称是“Real Tree”,是一种专门为处理多维空间数据(尤其是二维空间数据,如地理坐标)设计的树形数据结构。 简单来说,它就像是一个特殊的目录,将空间数据按照它们的位置…

蝙蝠优化算法(bat optimization algorithm)

注意:本文引用自专业人工智能社区Venus AI 更多AI知识请参考原站 ([www.aideeplearning.cn]) 算法背景 蝙蝠优化算法(Bat Algorithm)是一种基于群体智能的优化算法,它的灵感来源于蝙蝠捕食时的回声定位行…

蓝桥杯刷题-15-异或和之和-拆位+贡献法⭐⭐(⊙o⊙)

蓝桥杯2023年第十四届省赛真题-异或和之和 题目描述 给定一个数组 Ai,分别求其每个子段的异或和,并求出它们的和。或者说,对于每组满足 1 ≤ L ≤ R ≤ n 的 L, R ,求出数组中第 L 至第 R 个元素的异或和。然后输出每组 L, R 得到…

Xlinx相关原语讲解导航页面

原语就是对FPGA底层器件的直接调用,与IP功能是类似的,将原语的参数变成IP配置时的GUI界面参数,可能会更加直观。IP的缺陷在于繁杂,比如SelectIO IP内部包含IDDR、ODDR等等IO转换的功能,如果只想使用单沿转双沿一个功能…

Leetcode刷题-字符串详细总结(Java)

字符串 字符串可能在算法处理上面和数组是类似的,但是String和数组的数据结构还是有一些不一样的 1、反转字符串 344. 反转字符串 - 力扣(LeetCode) 双指针的经典应用,两个指针同时向中间移动 public void reverseString(char[…

C语言进阶课程学习记录-第20课 - 链接过程简介

C语言进阶课程学习记录-第20课 - 链接过程简介 链接器静态链接实验-静态链接源代码生成目标文件打包生成静态库文件直接编译使用静态库编译 动态链接实验-动态链接源代码生成动态链接库文件直接编译使用动态链接库编译运行test.out删除dlib.so运行test.out 小结 本文学习自狄泰…

【算法】二分算法题

个人主页 : zxctscl 如有转载请先通知 题目 1. 704. 二分查找1.1 分析1.2 代码 2. 34. 在排序数组中查找元素的第一个和最后一个位置2.1 分析2.2 代码 3. 35. 搜索插入位置3.1 分析3.2 代码 4. 852. 山脉数组的峰顶索引4.1 分析4.2 代码 5. 153. 寻找旋转排序数组中…

nexus设置s3存储

问题 因为我的nexus是安装在EC2上面,需要利用s3的存储能力,为nexus提供存储服务。 步骤 准备s3桶 输入桶名,创建s3桶,如下图: 创建桶读写策略 具体内容如下: {"Version": "2012-10-1…

【数据分享】我国第七次人口普查的100m分辨率人口栅格数据(免费获取\tif格式\2020年)

人口空间分布数据是我们在各项研究中经常使用的数据。之前我们分享过来源于LandScan数据集的2000-2022年的1km精度的人口空间分布栅格数据(可查看之前的文章获悉详情)! 相较于LandScan全球人口数据集,我国历次人口普查的数据对于…

AI服务平台replicate

Replicate是一个提供优秀AI模型和工具的平台,旨在帮助用户实现各种人工智能任务。该平台汇集了来自各个领域的顶尖模型,涵盖了文本到图像生成、语言模型、图像编辑、超分辨率等多个领域。用户可以通过Replicate平台快速获取和应用先进的模型,…

【C++】优先级队列(priority_queue)的用法与实现

目录 一、概念: 二、仿函数(Functor): 概念: 应用: 三、底层实现: 基本操作: 完整代码: 测试示例: 一、概念: 优先级队列(pri…

小白水平理解面试经典题目1431. Kids With the Greatest Number of Candies【Array类】

个人专栏 🤺 leetcode 🧗 Leetcode Prime 🏇 Golang20天教程 🚴‍♂️ Java问题收集园地 🌴 成长感悟 欢迎大家观看,不执着于追求顶峰,只享受探索过程 1431. 拥有最多糖果的孩子 小白渣翻译 一…

蓝桥杯刷题-17-平方差-打表+数学⭐(⊙o⊙)

之前的题目:最大也就到2e5左右。1e9的数据范围就意味着,即使是O(n)的复杂度,也会超时。此时可以考虑使用数学方法进行解题。 ❗打表:利用电脑去找一些合法答案,然后在这些合法答案中找规律。 ⭐打表后找到的规律: (1)好像所有的奇数都是合法…

spikingjelly训练自己的网络---量化 --测试

第二个 但是我发现,都要反量化,因为pytorch是只能支持浮点数的。 https://blog.csdn.net/lai_cheng/article/details/118961420 Pytorch的量化大致分为三种:模型训练完毕后动态量化、模型训练完毕后静态量化、模型训练中开启量化,…

Java 解决 Process 执行命令行命令报【CreateProcess error=2, 系统找不到指定的文件。】错误问题

目录 问题 问题代码 解决方案 判断操作系统 问题 使用 Process 执行命令行命令时,报 CreateProcess error2, 系统找不到指定的文件。但明明指定的文件是存在的。而且这种错误只在 IDEA 中运行会报错,打包后直接 java -jar 运行就能正常运行&#xf…

国产DSP FT-M6678开发-中断开发

全局中断控制器(CIC) FT-M6678 芯片集成了众多的外设,这些外设都可产生中断事件源,这些中断事件如何被服务取决于用户的特殊应用。在FT-M6678 芯片中,EDMA 和CorePac 都能够为事件服务,为了最大限度的增加系…

vue3第十六节(keep-alive 内置组件)

keep-alive 1、目的 在使用组件时,有时我们需要将组件进行缓存,而不是重新渲染,用以提高性能,避免重复加载DOM,提升用户的体验; keep-alive 组件可以做到这一点,它允许你缓存组件实例&#xf…

家用洗地机哪个牌子好?四大热销机型推荐,值得推荐!

随着科技的进步,洗地机在日常生活中能够帮助人们省时省力地打扫卫生,但市面上出现了各种各样的洗地机,好坏参差不齐,选择一个好品牌的洗地机非常重要,因为它们有着可靠的质量保证。那市面上如此众多的洗地机品牌&#…

Python爬虫之分布式爬虫

分布式爬虫 1.详情介绍 分布式爬虫是指将一个爬虫任务分解成多个子任务,在多个机器上同时执行,从而加快数据的抓取速度和提高系统的可靠性和容错性的技术。 传统的爬虫是在单台机器上运行,一次只能处理一个URL,而分布式爬虫通过将…

关于阿里云centos系统下宝塔面板部署django/中pip install mysqlclient失败问题的大总结/阿里云使用oss长期访问凭证

python版本3.12.0 问题1 解决方案 sudo vim /etc/profile export MYSQLCLIENT_CFLAGS"-I/usr/include/mysql" export MYSQLCLIENT_LDFLAGS"-L/usr/lib64/mysql" Esc退出编辑模式 :wq退出并且保存 问题二 说是找不到 mysql.h头文件 CentOS ‘…