当前位置: 首页 > news >正文

C语言入门系列:数据类型转换

文章目录

  • 一,自动类型转换
    • 1,赋值运算
      • 1.1,浮点数赋值给整型变量-不安全
      • 1.2,整数赋值给浮点数变量-安全
      • 1.3,窄类型赋值给宽类型-安全
      • 1.4,宽类型赋值给窄类型-不安全
    • 2,混合类型的运算
      • 2.1,整形和浮点数混合
      • 2.2,不同的浮点数类型混合
      • 2.3,不同的整数类型混合
    • 3,整数类型的运算
    • 4,函数
  • 二,强制类型转换

在这里插入图片描述

当不同数据类型的数据出现在同一个表达式中时,就会涉及数据类型转换,C语言中的数据类型转换有两种:

  • 自动类型转换
  • 强制类型转换

类型转换可能是安全的,即不会丢失数据;也可能是不安全的,即出现丢失数据的情况。

窄类型转换为宽类型,是安全的,不会丢失数据。

宽类型转换为窄类型,是不安全的,虽然不是百分百丢失数据,但有丢失数据的可能。

一,自动类型转换

自动类型转换是指在特点情况下,编译器将一种数据类型自动转换为另一种类型,自动类型转换可能是安全的,也可能是不安全的,即可能出现数据丢失。

1,赋值运算

赋值运算符左右两边的数据类型不一致时,会以变量的类型为准,将右边的值转成变量的类型。

1.1,浮点数赋值给整型变量-不安全

浮点数赋予整型变量时,C语言的转换过程简单粗暴,保留整数部分,丢弃小数部分。

int x = 3.14159627;

如上,变量x被声明为整型,然后赋一个double类型值。

编译器会把3.14159627转为整形,小数部分0.14159627会被丢弃(注意,不是四舍五入),保留整数3,3被赋值给变量x,因此变量x的值是3。

显然,这种情况下的自动类型转换导致数据丢失,是不安全的类型转换,我们在编写代码时,要避免类似的赋值语句,左右两边的类型一致才是最佳实践。

1.2,整数赋值给浮点数变量-安全

整型赋值给浮点数变量时,会自动转为浮点数。

float y = 12 * 2;

上面示例中,变量y的值不是24,而是24.0,因为等号右边的整数自动转为了浮点数。

C语言中的浮点数遵循了IEEE 754标准,使用科学计数法来存储浮点数,其数组范围被整形要大得多,所以整形赋值给浮点数,不会出现数据丢失,是安全的自动类型转换。

1.3,窄类型赋值给宽类型-安全

字节宽度较小的整数类型,赋值给字节宽度较大的整数变量时,会发生类型提升,即窄类型自动转为宽类型。

比如,char或short类型赋值给int类型,会自动提升为int。

char x = 100;
int i = x + y;

上面示例中,变量x的类型是char,由于赋值给int类型,所以会自动提升为int。

1.4,宽类型赋值给窄类型-不安全

字节宽度较大的类型,赋值给字节宽度较小的变量时,会发生类型降级,自动转为后者的类型。这时可能会发生截断,系统会将移除的高位二进制,从而出现意料之外的情况。

int i = 321;
char ch = i; // ch 的值是 65 (321 % 256 的余值)

上面例子中,变量ch是char类型,宽度是8个二进制位。

变量i是int类型,将i赋值给ch,后者只能容纳i(二进制形式为101000001,共9位)的后八位,前面多出来的二进制位被丢弃,保留后八位就变成了01000001(十进制的65,相当于字符A)。

之前介绍的浮点数赋值给整型变量,也属于宽类型自动转换为窄类型,也会发生截断,丢弃小数部分。

double pi = 3.14159;
int i = pi; // i 的值为 3

上面示例中,i等于3,pi的小数部分被截去了。

2,混合类型的运算

不同类型的值进行混合计算时,必须先转成同一个类型,才能进行计算。转换规则如下:

2.1,整形和浮点数混合

整数与浮点数混合运算时,整数转为浮点数类型,与另一个运算数类型相同。

3 + 1.2 // 4.2

上面示例是int类型与float类型的混合计算,int类型的3会先转成float的3.0,再进行计算,得到4.2。

2.2,不同的浮点数类型混合

运算时,宽度较小的类型转为宽度较大的类型,比如float转为double,double转为long double。

2.3,不同的整数类型混合

运算时,宽度较小的类型会提升为宽度较大的类型。

比如short转为int,int转为long等,有时还会将带符号的类型signed转为无符号unsigned。

下面例子的执行结果,可能会出人意料。

int a = -5;
if (a < sizeof(int)do_something();

上面示例中,变量a是带符号整数,sizeof(int)是size_t类型,这是一个无符号整数。

按照规则,signed int 自动转为 unsigned int,所以a会自动转成无符号整数4294967291(转换规则是-5加上无符号整数的最大值,再加1),导致比较失败,do_something()不会执行。

所以,最好避免无符号整数与有符号整数的混合运算。因为这时 C 语言会自动将signed int转为unsigned int,可能不会得到预期的结果。

3,整数类型的运算

两个相同类型的整数运算时,或者单个整数的运算,一般来说,运算结果也属于同一类型。

但是有一个例外,宽度小于int的类型,运算结果会自动提升为int。

unsigned char a = 66;if ((-a) < 0) printf("negative\n");
else printf("positive\n");

上面示例中,变量a是 unsigned char 类型,这个类型不可能小于0,但是-a不是 unsigned char 类型,会自动转为 int 类型,导致上面的代码输出 negative。

再看下面的例子。

unsigned char a = 1;
unsigned char b = 255;
unsigned char c = 255;if ((a - 5) < 0) do_something();
if ((b + c) > 300) do_something();

上面示例中,表达式a - 5和b + c都会自动转为 int 类型,所以函数do_something()会执行两次。

4,函数

函数的参数和返回值,会自动转成函数定义里指定的类型。

int dostuff(int, unsigned char);char m = 42;
unsigned short n = 43;
long long int c = dostuff(m, n);

上面示例中,参数变量m和n不管原来的类型是什么,都会转成函数dostuff()定义的参数类型。

下面是返回值自动转换类型的例子。

char func(void) {int a = 42;return a;
}

上面示例中,函数内部的变量a是int类型,但是返回的值是char类型,因为函数定义中返回的是这个类型。

二,强制类型转换

最佳实践是,我们在编写代码时,应该避免自动类型转换,因为自动类型转换可能导致出现意料之外的情况。

代码的行为始终在程序员的预料之中,是程序员必须追求的目标。

对于必不可少的类型转换,最好是使用强制类型转换

强制类型转换是指在一个值或变量的前面,使用圆括号指定类型(type),称之为casting。

(unsigned char) ch

上面示例将变量ch转成无符号的字符类型。

char c = (char)266;

上面示例中,(char)将266强制转换为char类型。

首先,虽然从语法上看,这种转换是没有必要的,因为对于赋值运算来说,编译器会把右边的值自动转换为左边的类型。但是,这样的代码是我们推荐的写法,更直观,便于阅读。

其次,把整型266强制转换为char类型,会出现数据截断,导致部分数据丢失,但由于这是我们意料之中的情况,就不会出现安全问题。

相关文章:

  • 【深度学习】实现基于MNIST数据集的TensorFlow/Keras深度学习案例
  • Vue-内容渲染,属性渲染指令
  • 【深度学习】GPT-3,Language Models are Few-Shot Learners(一)
  • ShareX,屏幕截图、屏幕录制和文件共享,还提供了丰富的高级功能和自定义选项
  • 建造者模式(大话设计模式)C/C++版本
  • 35.简易远程数据框架的实现
  • Leetcode85
  • 软件测试笔记
  • IPv6 中 MAC 33:33 的由来
  • VisualBox 虚拟机 Ubunut 18.04 在大显示器上黑屏的问题
  • 【LinuxC语言】网络编程的本质
  • 动态ARP
  • TCP 协议详解:三次握手与四次挥手
  • 一篇快速教你如何创建专业级数据可视化库
  • 开启数字新纪元:全球首款开源AI女友,你的私人数字伴侣
  • 【108天】Java——《Head First Java》笔记(第1-4章)
  • 【腾讯Bugly干货分享】从0到1打造直播 App
  • centos安装java运行环境jdk+tomcat
  • Java程序员幽默爆笑锦集
  • MySQL几个简单SQL的优化
  • php ci框架整合银盛支付
  • PHP 程序员也能做的 Java 开发 30分钟使用 netty 轻松打造一个高性能 websocket 服务...
  • Transformer-XL: Unleashing the Potential of Attention Models
  • windows下使用nginx调试简介
  • 服务器之间,相同帐号,实现免密钥登录
  • 聊聊redis的数据结构的应用
  • 如何合理的规划jvm性能调优
  • 微信小程序设置上一页数据
  • 如何通过报表单元格右键控制报表跳转到不同链接地址 ...
  • #HarmonyOS:基础语法
  • (Java)【深基9.例1】选举学生会
  • (undone) MIT6.824 Lecture1 笔记
  • (二)换源+apt-get基础配置+搜狗拼音
  • (附源码)springboot车辆管理系统 毕业设计 031034
  • (附源码)ssm高校升本考试管理系统 毕业设计 201631
  • (每日持续更新)jdk api之FileReader基础、应用、实战
  • (每日一问)基础知识:堆与栈的区别
  • (十三)MipMap
  • (四) Graphivz 颜色选择
  • (一)使用Mybatis实现在student数据库中插入一个学生信息
  • (转)关于如何学好游戏3D引擎编程的一些经验
  • (转)用.Net的File控件上传文件的解决方案
  • (自用)网络编程
  • (最完美)小米手机6X的Usb调试模式在哪里打开的流程
  • .[hudsonL@cock.li].mkp勒索加密数据库完美恢复---惜分飞
  • .“空心村”成因分析及解决对策122344
  • .config、Kconfig、***_defconfig之间的关系和工作原理
  • .NET Core引入性能分析引导优化
  • .Net 垃圾回收机制原理(二)
  • .NET8.0 AOT 经验分享 FreeSql/FreeRedis/FreeScheduler 均已通过测试
  • .net开发引用程序集提示没有强名称的解决办法
  • .ui文件相关
  • :=
  • @RequestMapping-占位符映射
  • [120_移动开发Android]008_android开发之Pull操作xml文件