【c/c++】类型转换:隐式类型转换、强制类型转换

news2024/11/14 23:56:39


目录

前言

一、了解类型转换

二、隐式类型转换

1.适用场景

2.转换规则

三、强制类型转换

适用场景

使用规则

注意事项


前言

类型转换是编程中一个常见的现象。在我们进行编码的时候不经意间就发生了,但却能让整个程序运行得更加流畅。

但是这种不经意,实在过于隐形和丝滑,很可能就给我们带来不少bug。

所以我们需要了解类型转换以及对应得出现场景。

一、了解类型转换

变量的类型间是可以互相转换的,转换又分为自动转换和强制转换

C/C++中的类型转换主要有四种:隐式类型转换、C风格类型转换、C++的static_cast、const_cast、reinterpret_cast以及dynamic_cast。

这里,我们先了解隐式类型转换和C风格类型转换,然后再介绍C++的四种类型转换操作符。

  1. 隐式类型转换(Implicit type conversion):编译器在需要的情况下自动进行的类型转换。例如,从较小的整数类型转换为较大的整数类型,或者从整数类型转换为浮点类型。在这种情况下,编译器会生成类型转换的指令,以确保在运行时数据被正确地转换。
char c = 'A';
int i = c + 1;  // 'A' 隐式地转换为了它的 ASCII 值 65
  1. C风格类型转换(C-style type casting):也可以成为强制类型转换。这种类型转换使用类型名作为转换操作符,语法为(type)expression。例如,将整数转换为浮点数:float x = (float)int_value;。C风格类型转换是强制性的,它可能导致一些意想不到的结果,因为它允许将任意类型转换为另一种类型。在底层,C风格类型转换通常通过生成与隐式类型转换相似的指令来实现。
double a = 10.5;
int b = (int)a; //a被强制转为int类型

二、隐式类型转换

1.适用场景

  • 自动转换是C++编译器自动完成的类型转换。
  • 当两个不同类型的数据进行运算时,编译器会自动将它们转换为相同的类型(优先转换为较高类型计算),以便进行运算。
  • 自动转换的特点:简单、方便,无需手动进行类型转换,可以提高编程效率。
  • 但是,自动转换也存在一些问题。由于编译器自动进行类型转换,有时候会出现意料之外的结果。例如,当一个整数和一个浮点数相加时,编译器会自动将整数转换为浮点数,但是由于浮点数的精度问题,可能会导致结果出现误差。因此,在进行自动转换时,需要注意精度问题。
  • 自动转换适用于一些简单的类型转换场景

    例如整型和浮点型之间的转换,可以通过自动转换来实现。

2.转换规则


1、若参与运算量的类型不同,为了提高效率,C /C++语言对于不同的两个类型将直接转换成较高类型计算。


int a =5;
double b = 6.6;
cout << a + b << endl; //结果为double类型


 类型优先级



2. float、double、long double 类型赋值给整数类型:直接截断小数


#include <stdio.h>

int main() {
  float a = 3.8;
  int b = a;  //进行了一次隐式类型转换
  printf("a=%.2f; b=%d", a, b);
  return 0;
}

输出结果:

a=3.80; b=3


3. 整数类型赋值给浮点数(float、double、long double)类型:补足有效小数位


对上述代码进行修改:

#include <stdio.h>

int main() {
  int a = 8;
  float b = a;  //进行了一次隐式类型转换
  printf("a=%d; b=%f", a, b);
  return 0;
}

结果:

a=8; b=8.000000  //%f默认输出6位小数


4. 存储长度较短的类型赋值给存储长度较长的类型:补足有效位,其它位补 0


但是本身数值不改变。

char c = 56;
short num = 67;
int m;
long long int n;

//执行下面得赋值语句
m = ((int)c);
n = ((long long)num);

补0过程

                                                               00111000  //Binary of 'c'
                                                      00000000 01000011  //Binary of 'num'
                                    00000000 00000000 00000000 00111000  //Binary of 'm'
00000000 00000000 00000000 00000000 00000000 00000000 00000000 01000011  //Binary of 'n'

输出结果:


5. 存储长度较长的类型赋值给存储长度较短的类型:舍弃高位(但保留符号),截断低字节给存储长度较短的类型


#include <iostream>
using namespace std;

int main() {
	long long int l = 223372036854775807;

	int i = (int)l;

	cout << l << endl;
	cout << i << endl;

	
	return 0;

}

它们在内存以2进制格式分别存储为:

00000011 00011001 10010011 10101111 00011101 01111011 11111111 11111111  //Binary of 'l'
                                    00011101 01111011 11111111 11111111  //Binary of 'v'

结果:


6. unsigned类型赋值给非unsigned类型:直接传递数值


注意:如果 unsigned 类型储存的量太大,强制类型转换后可能会出现非 unsigned 类型的值的绝对值不等于 unsigned 类型的值的绝对值的情况。

说到 “unsigned 类型储存的量太大”,顺带说一下,虽然 printf 输出 int 和 unsigned int 时可以混用 %d(或%i)和 %u(或%ui),但还是建议输出 int 类型的时候用 %d(或%i),输出 unsigned int 类型时用 %u(或%ui)(其它类型同理<如%ul等>)

看一个例子:

#include <stdio.h>

int main() {
	unsigned int x = 4294967295;  //这个数字为(2^32)-1, 而int类型最大存储数字的值为(2^31)-1
	int y = ((int)x);				//x强制转为了 int (unsigned int => int)


	printf("signed of x= %d", x);  //这里有一次隐式类型转换(unsigned int => int)
	putchar('\n');
	printf("unsigned of x= %u\n", x);
	printf("signed of y= %d", y);


	return 0;
}

可是因为隐式类型转换,结果输出为:

-1

4294967295

-1

出现“-1”的这个输出就是因为“unsigned类型储存的量太大(大于了同类型但非unsigned的类型)”

p.s: 不一定都为 -1,具体要看 unsigned 类型的值的 2 进制

7、非 unsigned 类型赋值给 unsigned 类型:直接传递数值

给个小技巧:如果你想“临时”给一个不知道正负的非 unsigned 类型的变量加上绝对值,可以使用abs函数,但利用(unsigned)(非unsigned类型变量名)可以节省一点内存开销

但是也有弊端:可能会出现 unsigned-unsigned 永远大于 0 的情况(不确定)

最后补充一下,强制类型转换只是临时类型转换,并不影响变量本身储存的值,看如下代码:

#include <stdio.h>
int main() {

	float a = 6.9;
	printf("%.3f", a);
	putchar('\n');

	((int)a);
	printf("%.3f", a);

	return 0;
}

输出结果:

6.900

6.900

三、强制类型转换

适用场景

而强制转换适用于一些需要精确控制类型转换的场景,例如将一个浮点数转换为整数,或者将一个指针类型转换为另一种类型时,需要使用强制转换。

在实际编程中,需要根据具体的场景选择适合的类型转换方式。如果不确定应该使用哪种类型转换方式,可以先使用自动转换,然后进行必要的验证和调整。如果需要更精确地控制类型转换的结果,可以使用强制转换,但是需要进行必要的检查和验证,以避免出现错误。

使用规则

强制类型转换是通过类型转换运算来实现的。

其一般形式为:(类型说明符)(表达式)其功能是把表达式的运算结果强制转换成类型说明符所表示的类型.

比如:

#include <iostream>

using namespace std;
int main() {

	double a = 10.1;
	cout << (int)a << endl;//发生了强转,double -> int

	return 0;
}

注意事项

强制类型转换是一种非常强大的工具,它可以将一个变量的类型转换为另一种类型。但是,强制类型转换也存在一些潜在的安全问题,需要特别注意。在介绍强制类型转换时,需要说明类型转换的安全性,并解释如何避免可能的类型转换错误。

1.类型转换失败的可能性

在使用强制类型转换时,可能会出现类型转换失败的情况,例如:

  • 当将一个浮点数转换为整数时,可能会出现精度损失的问题。
  • 当将一个指针类型转换为另一种类型时,可能会出现指针错误或者内存泄漏的问题。
  • 当将一个常量数据进行强制类型转换时,可能会出现未定义行为的问题。

2. 如何避免类型转换错误

为了避免类型转换错误,需要进行必要的检查和验证。具体而言,可以采取以下几个措施:

  • 在进行强制类型转换之前,需要对变量进行必要的检查和验证,确保转换是安全的。
  • 在将一个浮点数转换为整数时,需要注意精度问题,并进行必要的四舍五入。
  • 在将一个指针类型转换为另一种类型时,需要确保指针指向的内存空间是有效的,并且转换后的类型可以正确处理指针的值。
  • 在使用const_cast时,需要确保不会更改常量数据,否则会引发未定义行为。如果需要更改常量数据,可以使用其他类型转换方式,例如reinterpret_cast。

需要注意的是,在进行类型转换时,需要保证程序的正确性和安全性。如果不确定类型转换是否安全,可以先进行必要的验证和测试,确保程序运行正确。同时,需要遵循C++的类型转换规则,并严格遵守语言的规范。这样,就可以避免类型转换错误,提高程序的可靠性和安全性。

 


💗感谢阅读!💗


参考文章:

【C/C++ 类型转换规则】一文了解C/C++ 中的类型转换规则,帮助你更好的编程-阿里云开发者社区

【C++入门到精通】C++类型的转换 | static_cast | reinterpret_cast | const_cast | dynamic_cast [ C++入门 ]-阿里云开发者社区 

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

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

相关文章

C++:STL之vector

1.vector的使用 1.1vector的定义 使用vector需要包含头文件 #include<vector> vector的构造 &#xff08;constructor&#xff09;构造函数声明接口说明vector() (重点)无参构造vector(size_type n,const value_type& val value_type())用n个val初始化并构造vecto…

Java11环境安装(Windows)

目录 1 Java11安装2 配置2.1 JavaHome配置2.2 CLASSPATH配置PATH路径配置 3 验证 1 Java11安装 从官网下载Java11安装包&#xff1a;jdk-11_windows-x64_bin.exe,安装时选择安装到D:\Java目录。 安装完目录结构如下&#xff1a; 2 配置 2.1 JavaHome配置 如下图所示配置JAV…

Ubuntu构建只读文件系统

本文介绍Ubuntu构建只读文件系统。 嵌入式系统使用过程中&#xff0c;有时会涉及到非法关机&#xff08;比如直接关机&#xff0c;或意外断电&#xff09;&#xff0c;这可能造成文件系统损坏&#xff0c;为了提高系统的可靠性&#xff0c;通常将根文件系统设置为只读&#xf…

Linux下进程间的通信--信号量

前言&#xff1a; 资源竞争&#xff1a; 资源竞争&#xff08;Race Condition&#xff09;是多线程或多进程环境中的一种常见问题&#xff0c;它发生在多个进程或线程并发访问和修改同一资源&#xff08;如内存位置、文件、数据库记录等&#xff09;时&#xff0c;而最终结果…

mysql学习教程,从入门到精通,SQL AND OR 运算符(12)

1、SQL AND & OR 运算符 在本教程中&#xff0c;您将学习如何在子句中使用ASELECT column1_name, column2_name, columnN_nameFROM table_nameWHERE condition1 AND condition2;ND&#xff06;OR运算符&#xff0c;WHERE以根据多个条件过滤记录。 1.1、根据条件选择记录 …

从代码直观理解Self-Attention和Cross-Attention的本质区别

Transformer的模型架构实际上非常简单&#xff0c;Self-Attention 和 Cross-Attention 仅仅是在 k, v上有所不同&#xff08;这里不讨论 mask&#xff09;。 论文原文&#xff1a;Attention Is All You Need 我们可以使用同一个 Attention 类来实现 Self-Attention 和 Cross-At…

day11-多线程

一、线程安全问题 线程安全问题出现的原因&#xff1f;存在多个线程在同时执行同时访问一个共享资源存在修改该共享资源 线程安全:多个线程同时修改同一个资源 取钱案例 小明和小红是一对夫妻&#xff0c;他们有一个共同的账户&#xff0c;余额是10万元 如果小明和小红同时来取…

速看!6款可以写论文的ai写作网站,这才是真正的论文神器!(含教程)

在当今信息爆炸的时代&#xff0c;AI写作工具的出现极大地提高了写作效率和质量。特别是对于需要撰写论文的学生和研究人员来说&#xff0c;这些工具提供了极大的便利。本文将重点介绍一款备受推荐的AI写作平台——千笔-AIPassPaper&#xff0c;并结合相关教程帮助用户更好地使…

【北京迅为】《STM32MP157开发板使用手册》- 第二十四章 STM32CubeIDE的初步使用

iTOP-STM32MP157开发板采用ST推出的双核cortex-A7单核cortex-M4异构处理器&#xff0c;既可用Linux、又可以用于STM32单片机开发。开发板采用核心板底板结构&#xff0c;主频650M、1G内存、8G存储&#xff0c;核心板采用工业级板对板连接器&#xff0c;高可靠&#xff0c;牢固耐…

校园水电费管理微信小程序的设计与实现+ssm(lw+演示+源码+运行)

校园水电费管理小程序 摘 要 随着社会的发展&#xff0c;社会的方方面面都在利用信息化时代的优势。互联网的优势和普及使得各种系统的开发成为必需。 本文以实际运用为开发背景&#xff0c;运用软件工程原理和开发方法&#xff0c;它主要是采用java语言技术和mysql数据库来…

基于SSM的学生信息管理系统(选课管理系统)的设计与实现 (含源码+sql+视频导入教程)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1 、功能描述 基于SSM的学生信息管理系统&#xff08;选课管理系统&#xff09;13拥有三种角色 管理员&#xff1a;学生管理、教师管理、专业管理、课程管理、审批管理、课程表管理、开课管理、教室管…

高德地图JS API加载行政区边界AMap.Polygon

&#x1f916; 作者简介&#xff1a;水煮白菜王 &#xff0c;一位资深前端劝退师 &#x1f47b; &#x1f440; 文章专栏&#xff1a; 高德AMap专栏 &#xff0c;记录一下平时在博客写作中&#xff0c;总结出的一些开发技巧✍。 感谢支持&#x1f495;&#x1f495;&#x1f49…

大模型LLM之SpringAI:Web+AI(二)

2.2.2、ChatModel API(聊天模型API) 聊天模型太多了,这里只写OpenAI和Ollama ChatModel和ChatClient区别:ChatClient针对的是所有模型,共用一个客户端。而ChatModel是针对各个模型实现的。 (1)OpenAI 自动配置 <dependency><groupId>org.springframework…

vue3 内置组件 <Suspense>

官方文档&#xff1a; <Suspense> 指南-Suspense 官方提示&#xff1a; <Suspense> 是一项实验性功能。它不一定会最终成为稳定功能&#xff0c;并且在稳定之前相关 API 也可能会发生变化。 <Suspense>是一个内置组件&#xff0c;用来在组件树中协调对异步依…

git删除本地分支报错:error: the branch ‘xxx‘ is not fully merged

git删除本地分支报错&#xff1a;error: the branch xxx is not fully merged error: the branch xxx is not fully merged 直接&#xff1a; git branch -D xxx 就可以。 如果删除远程分支&#xff1a; git push origin --delete origin/xxx git强制删除本地分支 git branc…

如何将Git本地代码推送到Gitee云端仓库

如何将Git本地代码推送到Gitee云端仓库 在使用Git进行版本控制时&#xff0c;将本地代码推送到远程仓库是一个基本且重要的操作。本文将详细介绍如何将你的Git本地代码推送到Gitee&#xff08;码云&#xff09;云端仓库。Gitee是一个国内非常流行的代码托管平台&#xff0c;类…

NX—UI界面生成的文件在VS上的设置

UI界面保存生成的三个文件 打开VS创建项目&#xff0c;删除自动生成的cpp文件&#xff0c;将生成的hpp和cpp文件拷贝到项目的目录下&#xff0c;并且在VS项目中添加现有项目。 修改VS的输出路径&#xff0c;项目右键选择属性&#xff0c;链接器中的常规&#xff0c;文件路径D:…

线性代数 第七讲 二次型_标准型_规范型_坐标变换_合同_正定二次型详细讲解_重难点题型总结

文章目录 1.二次型1.1 二次型、标准型、规范型、正负惯性指数、二次型的秩1.2 坐标变换1.3 合同1.4 正交变换化为标准型 2.二次型的主要定理3.正定二次型与正定矩阵4.重难点题型总结4.1 配方法将二次型化为标准型4.2 正交变换法将二次型化为标准型4.3 规范型确定取值范围问题4.…

《中国制药设备行业市场现状分析与发展前景预测研究报告》

报告导读&#xff1a;本报告从国际制药设备发展、国内制药设备政策环境及发展、研发动态、供需情况、重点生产企业、存在的问题及对策等多方面多角度阐述了制药设备市场的发展&#xff0c;并在此基础上对制药设备的发展前景做出了科学的预测&#xff0c;最后对制药设备投资潜力…

​​操作系统 ---- 进程调度的时机、切换与过程

目录 一、进程调度的时机 1.1 什么时候需要进行进程调度与切换&#xff1f; 1.2 什么情况下不能进行进程调度与切换&#xff1f; 二、进程调度的方式 2.1 非抢占方式(Nonpreemptive Mode) 2.2 抢占方式(Preemptive Mode) 三、总结 一、进程调度的时机 进程调度&am…