数据类型转换就是将数据(变量、数值、表达式的结果等)从一种类型转换为另一种类型。

自动类型转换

自动类型转换就是编译器默默地、隐式地、偷偷地进行的数据类型转换,这种转换不需要程序员干预,会自动发生。

1) 将一种类型的数据赋值给另外一种类型的变量时就会发生自动类型转换,例如:

float f = 100;

100 是 int 类型的数据,需要先转换为 float 类型才能赋值给变量 f。再如:

int n = f;

f 是 float 类型的数据,需要先转换为 int 类型才能赋值给变量 n。

在赋值运算中,赋值号两边的数据类型不同时,需要把右边表达式的类型转换为左边变量的类型,这可能会导致数据失真,或者精度降低;所以说,自动类型转换并不一定是安全的。对于不安全的类型转换,编译器一般会给出警告。

2) 在不同类型的混合运算中,编译器也会自动地转换数据类型,将参与运算的所有数据先转换为同一种类型,然后再进行计算。转换的规则如下:

  • 转换按数据长度增加的方向进行,以保证数值不失真,或者精度不降低。例如,int 和 long 参与运算时,先把 int 类型的数据转成 long 类型后再进行运算。
  • 所有的浮点运算都是以双精度进行的,即使运算中只有 float 类型,也要先转换为 double 类型,才能进行运算。
  • char 和 short 参与运算时,必须先转换成 int 类型。

下图对这种转换规则进行了更加形象地描述:

unsigned 也即 unsigned int,此时可以省略 int,只写 unsigned。

自动类型转换示例:

  1. #include<stdio.h>
  2. int main(){
  3. float PI = 3.14159;
  4. int s1, r = 5;
  5. double s2;
  6. s1 = r * r * PI;
  7. s2 = r * r * PI;
  8. printf("s1=%d, s2=%f\n", s1, s2);
  9. return 0;
  10. }

运行结果:
s1=78, s2=78.539749

在计算表达式r*r*PI时,r 和 PI 都被转换成 double 类型,表达式的结果也是 double 类型。但由于 s1 为整型,所以赋值运算的结果仍为整型,舍去了小数部分,导致数据失真。

强制类型转换

自动类型转换是编译器根据代码的上下文环境自行判断的结果,有时候并不是那么“智能”,不能满足所有的需求。如果需要,程序员也可以自己在代码中明确地提出要进行类型转换,这称为强制类型转换。

自动类型转换是编译器默默地、隐式地进行的一种类型转换,不需要在代码中体现出来;强制类型转换是程序员明确提出的、需要通过特定格式的代码来指明的一种类型转换。换句话说,自动类型转换不需要程序员干预,强制类型转换必须有程序员干预。

强制类型转换的格式为:

(type_name) expression

type_name为新类型名称,expression为表达式。例如:

  1. (float) a; //将变量 a 转换为 float 类型
  2. (int)(x+y); //把表达式 x+y 的结果转换为 int 整型
  3. (float) 100; //将数值 100(默认为int类型)转换为 float 类型

下面是一个需要强制类型转换的经典例子:

  1. #include <stdio.h>
  2. int main(){
  3. int sum = 103; //总数
  4. int count = 7; //数目
  5. double average; //平均数
  6. average = (double) sum / count;
  7. printf("Average is %lf!\n", average);
  8. return 0;
  9. }

运行结果:
Average is 14.714286!

sum 和 count 都是 int 类型,如果不进行干预,那么sum / count的运算结果也是 int 类型,小数部分将被丢弃;虽然是 average 是 double 类型,可以接收小数部分,但是心有余力不足,小数部分提前就被“阉割”了,它只能接收到整数部分,这就导致除法运算的结果严重失真。

既然 average 是 double 类型,为何不充分利用,尽量提高运算结果的精度呢?为了达到这个目标,我们只要将 sum 或者 count 其中之一转换为 double 类型即可。上面的代码中,我们将 sum 强制转换为 double 类型,这样sum / count的结果也将变成 double 类型,就可以保留小数部分了,average 接收到的值也会更加精确。

在这段代码中,有两点需要注意:

  • 对于除法运算,如果除数和被除数都是整数,那么运算结果也是整数,小数部分将被直接丢弃;如果除数和被除数其中有一个是小数,那么运算结果也是小数。这一点已在《C语言加减乘除运算》中进行了详细说明。
  • ( )的优先级高于/,对于表达式(double) sum / count,会先执行(double) sum,将 sum 转换为 double 类型,然后再进行除法运算,这样运算结果也是 double 类型,能够保留小数部分。注意不要写作(double) (sum / count),这样写运算结果将是 3.000000,仍然不能保留小数部分。

类型转换只是临时性的

无论是自动类型转换还是强制类型转换,都只是为了本次运算而进行的临时性转换,转换的结果也会保存到临时的内存空间,不会改变数据本来的类型或者值。请看下面的例子:

  1. #include <stdio.h>
  2. int main(){
  3. double total = 400.8; //总价
  4. int count = 5; //数目
  5. double unit; //单价
  6. int total_int = (int)total;
  7. unit = total / count;
  8. printf("total=%lf, total_int=%d, unit=%lf\n", total, total_int, unit);
  9. return 0;
  10. }

运行结果:
total=400.800000, total_int=400, unit=80.160000

注意看第 6 行代码,total 变量被转换成了 int 类型才赋值给 total_int 变量,而这种转换并未影响 total 变量本身的类型和值。如果 total 的值变了,那么 total 的输出结果将变为 400.000000;如果 total 的类型变了,那么 unit 的输出结果将变为 80.000000。

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

在C语言中,有些类型既可以自动转换,也可以强制转换,例如 int 到 double,float 到 int 等;而有些类型只能强制转换,不能自动转换,例如以后将要学到的 void * 到 int *,int 到 char * 等。

可以自动转换的类型一定能够强制转换,但是,需要强制转换的类型不一定能够自动转换。现在我们学到的数据类型,既可以自动转换,又可以强制转换,以后我们还会学到一些只能强制转换而不能自动转换的类型。

可以自动进行的类型转换一般风险较低,不会对程序带来严重的后果,例如,int 到 double 没有什么缺点,float 到 int 顶多是数值失真。只能强制进行的类型转换一般风险较高,或者行为匪夷所思,例如,char * 到 int * 就是很奇怪的一种转换,这会导致取得的值也很奇怪,再如,int 到 char * 就是风险极高的一种转换,一般会导致程序崩溃。

使用强制类型转换时,程序员自己要意识到潜在的风险。

C语言:数据类型转换 自动转换 强制转换的更多相关文章

  1. 3_PHP表达式_5_数据类型转换_类型强制转换

    以下为学习孔祥盛主编的<PHP编程基础与实例教程>(第二版)所做的笔记. PHP类型转换分为类型自动转换和类型强制转换. 3.5.2 类型强制转换 类型强制转换允许编程人员手动将变量的数据 ...

  2. C语言数据类型转换

    变量的数据类型是可以转换的.转换的方法有两种,一种是自动转换,一种是强制转换. 自动转换 自动转换发生在不同数据类型的量混合运算时,由编译系统自动完成.自动转换遵循以下规则: 若参与运算量的类型不同, ...

  3. R语言数据类型转换

    test for data type is.numeric(), is.character(), is.vector(), is.matrix(), is.data.frame() convert i ...

  4. 谷歌protobuf(protocol-buffers)各种开发语言数据类型转换说明

    官方文档:https://developers.google.cn/protocol-buffers/docs/proto proto2 proto3

  5. Java数据类型转换(自动转换和强制转换)

    数据类型的转换,分为自动转换和强制转换.自动转换是程序在执行过程中“悄然”进行的转换,不需要用户提前声明,一般是从位数低的类型向位数高的类型转换;强制类型转换则必须在代码中声明,转换顺序不受限制. 自 ...

  6. java类型转换详解(自动转换和强制转换)

    自动转换 class Hello { public static void main(String[] args) { //自动转换 int a = 5; byte b = 6; int c = a ...

  7. java语言中数值自动转换的优先顺序

    转换原则:从低精度向高精度转换byte .short.int.long.float.double.char数据类型的转换,分为自动转换和强制转换.自动转换是程序在执行过程中“悄然”进行的转换,不需要用 ...

  8. Java基础学习-类型转换之隐式转换

    +是一个运算符,我们应该能够看懂,做数据的加法. boolean类型不能转换为其他的数据类型. 默认转换:     byte,short,char--int--float--double     by ...

  9. 【java】学习路线1-类型转换、隐式转换、强制转换

    /**文档注释,这里是一段文章一般放在类的外面*/public class HelloWorld{    //这个是注释的文本    public static void main(String[] ...

随机推荐

  1. 内建函数 iter()

    可以选择接受一个无参的可调用对象以及一个哨兵(结束)作为输入.当已这种方式使用时,iter()会创建i一个迭代器,然后重复调用用户提供的可调用对象,直到返回哨兵的值为止. import sys wit ...

  2. AI推理单元

    AI推理单元 推理服务供了一套面向 MLU(Machine Learning Unit,机器学习单元)设备的类似服务器的推理接口(C++11标准),以及模型加载与管理,推理任务调度等功能,极大地简化了 ...

  3. MindSpore特性支持类

    MindSpore特性支持类 Q:请问MindSpore支持梯度截断吗? A:支持,可以参考梯度截断的定义和使用. Q:如何在训练神经网络过程中对计算损失的超参数进行改变? A:暂时还未有这样的功能. ...

  4. 前台JS遍历Table的所有单元格数据内容

    在日常开发过程中为了减少与后台服务器的交互次数,大部分的功能都会放到前台使用JS来完成. 例如:一个表中有ID(FOCUS_SEQ)和Name(COLUMNCTRL)两个字段,其中ID是自定义连续增长 ...

  5. 面试一次问一次,HashMap是该拿下了(一)

    文章目录 前言 一.HashMap类图 二.源码剖析 1. HashMap(jdk1.7版本) - 此篇详解 2. HashMap(jdk1.8版本) 3. ConcurrentHashMap ~~ ...

  6. 【题解】Luogu p3478 [POI2008]STA-Station 动态规划

    题目描述 给出一个$N$个点的树,找出一个点来,以这个点为根的树时,所有点的深度之和最大 输入输出格式 输入格式 第一行一个数$n$,表示树上共有$n$个点接下来$n-1$行,表示$n-1$条边;每行 ...

  7. 从谭浩强的《C语言程序设计》到《电容应用分析精粹》

    不记得具体从什么时候开始(反正很多年前的事了)的,不少人都陆续批评过谭浩强的<C语言程序设计>,各方面都有扒过.例如,与实践脱节,很多例子在不同编译器上运行是错误的,代码风格糟糕等等方面. ...

  8. 轻松吃透实时时钟芯片DS1302软硬件设计,看完秒懂

    今天我们来讨论一款老掉牙的实时时钟芯片DS1302.什么是实时时钟(RealTime Clock, RTC)呢?为什么我们需要它呢?假设你使用单片机实现万年历应用,一般的做法是这样的:设置中断后判断1 ...

  9. Java基础-封装和继承

    @ 目录 Java基础知识(封装和继承) 一. 封装 1.1 封装的目的 1.2 封装的好处 1.3 封装的步骤 1.4 封装的例子 1.5 小结 二. 继承 2.1 继承的介绍 2.2 生活中的继承 ...

  10. 陋居寡闻,初探Github CLI For Windows,开启命令行撸铁时代

    简介 gh is GitHub on the command line. It brings pull requests, issues, and other GitHub concepts to t ...