浅谈C++类型转换几种情况

目录
  • 0. 类型转换的原理
  • 1. 初始化和赋值时进行的转换
  • 2. 以{}方式初始化时进行的转换(C++11新增)
  • 3. 表达式中的转换
  • 4. 传递参数时的转换
  • 5. 强制类型转换
  • 6. 使用auto让编译器自己推断变量类型

0. 类型转换的原理

在进行下面的学习前,我觉得有比较知道不同类型是怎么进行转换的。

int a = 777777;
//二进制为00000000 01110110 10101101 11110001
short b = a;
//b只有2字节,从低位开始截断,只能存10101101 11110001 注意,这并不是b的最终答案,
//我们应该知道,计算机中数值都是以二进制补码的形式存储的,所以我们需要将10101101 11110001还原为原码,
//也就是11011110 00110001,最高位是符号位,转换为十进制就是-8655
 cout << b;

而浮点数转整形,不但会进行上述过程还会进行小数截断。

1. 初始化和赋值时进行的转换

 int int_a = 123;
 long long  int llong_a = int_a;
 //赋值的时候,编译器会先将int类型的123扩展为long类型123的新值,然后赋值给long_b,原先的int_a还是int类型,
 //没有变化。
 cout << "llong_b所占内存: " << sizeof(llong_a)<< "   值为:  "
 << llong_a << "  int_a的类型:" << sizeof(int_a) << endl;
 //通常情况下,小范围转大范围这样赋值是没有问题,但是如果大范围转小范围可能回来带来一些麻烦,
 //如果大范围的数值在小范围之内,这也是没有问题的,如果该数值不在小范围之内会发生什么呢
 //long long int 最大值为9223372036854775807
 //而int的最大值为2147483647 我们来做个实验:
 long long int llong_b = 9223372036854775807;
 int int_b = llong_b;
 cout << "\nllong_b所占内存: " << sizeof(int_b) << "   值为:  "
 << int_b << "  int_a的类型:" << sizeof(llong_b) << endl;
 //出现了问题,int_b的值只有-1,连自己本身类型的最大值都没有赋到。

运行结果:

小范围类型赋值给大范围类型是可以的,大范围赋值给小范围,要考虑好是否超出最大值,通常只会复制低位,建议不要这样做。

上面说的是整形类型的转换,如果是浮点数转换的话也会有两个问题:

1.将较大的浮点型转换为较小的浮点类型,精度降低(如果对精度不理解请看我的C++第一篇),值可能会超出目标类型的取值范围,这种情况下的值是不确定的。

2.将浮点型转换为整形,小数部分会被截断,原来的值可能超出目标类型的取值范围,这种情况下的值也是不确定的。

2. 以{}方式初始化时进行的转换(C++11新增)

用{}这种方式来转换类型是C++11新增的内容,它更为严格,不允许需要转换的类型进行缩窄,什么意思呢,就是要保证涉及到需要转换的类型应该是和需要完成的类型应该是一样长的,比如,int有4位,long long 有8位,long long想转为int,就必须将从左往右的4位截断,这就是缩窄。

 const int code = 66;
 int x = 66;
 char c1{ 31325 }; //错误
 char c2 = { 66 };
 char c3 = { code };
 char c4 = { x }; // 错误
 x = 31325;
 char c5 = x;

代码的语法没有任何问题,但是编译运行时会出现:

第一个错误好理解一点,31325远远超过了char的最大范围。
第二个错误明明x的值为66,为什么会出错呢?编译器不会管你x的值是多大,他只管x的类型是多大。
而最后c5被赋予31325这个值,由于没有使用{}处理,并没有保存,但其结果是不确定的。
而浮点数转为整形,即使符合也不被允许:

 long long int a = {10.12f};
 long long int b = { 10.12 };

而整形转浮点数,只要符合缩窄条件,就可以被转换。

3. 表达式中的转换

下面是C++11版本的校验表,编译器将按照下表依次执行。

1.如果有一位操作数的类型是long double,则另一个操作数转换为long double。

2.否则,如果有一个操作数的类型是double,则另一个操作数转换为double。

3.否则,如果有一个操作数的类型float,则另一个操作数转换为float。

4.否则,说明操作数都是整形的,因此执行整形提升,什么是整形提升,下面有写。

5.在整形提升的情况下,如果两个操作数都是有符号或者无符号类型的,且其中一个操作数的级别比另一个低,则转换为最高级别的类型。

6.如果一个操作数为有符号的,另一个操作数是无符号的,且无符号操作数的级别比有符号操作数的级别高,则将有符号操作数转换为无符号操作数所属的类型。

7.否则,如果有符号类型可以表示无符号类型的所有可能取值,则将无符号操作数转换为有符号操作数所属的类型。

8.否则,将两个操作数都转换为有符号类型的无符号版本。

整形提升:
如果bool,char、short,包括它们有符号或无符号变型,以及枚举类型,可以使用在需要int或者unsigned int的表达式中。如果int可以完整表示源类型的所有值,那么该源类型的值就转换为int,否则转换为unsigned int。这称为整型提升。

4. 传递参数时的转换

如果函数参数类型定义为double类型,但是传入的时int类型,这在C中会提示错误,但在C++中,C++会自动帮我我们转换为函数原型中定义的值,条件是两种都是算术类型。也可以手动取消这种自动,在这种情况下,C++将对char和short类型进行整形提升,将float转为double类型。

5. 强制类型转换

C++允许用户自己强制转换变量的类型,C++自己规定的类型转换规则有时候可能并不适合用户,并且被转的变量本身并没有有任何影响。

int a = 66;
(long)a;// 这种是C的风格
long(a);// 这种是C++的风格,应尽量使用这种。

6. 使用auto让编译器自己推断变量类型

C++新增的一个工具,让编译器能够根据初始值的类型推断变量的类型,像是js中的var,这个东西就是C语言中的关键字auto。

auto a = 666;//编译器将为a定义为int类型
auto b = 66.66f;//编译器将为b定义为float类型,注意数值后面的f

除了我上面写的,C++还引入了4个强制类型转换运算符,由于我还没有学到那里,就不写了,嘿嘿。

到此这篇关于浅谈C++类型转换几种情况的文章就介绍到这了,更多相关C++ 类型转换内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++中的四种类型转换

    1 引子 这篇笔记是根据StackOverflow上面的一个问题整理而成,主要内容是对C/C++当中四种类型转换操作进行举例说明.在之前其实对它们都是有所了解的,而随着自己在进行总结,并敲了一些测试示例代码进行验证之后,对它们的理解又深刻了一些. 总所周知,在C++ 当中引入了四种新的类型转换操作符:static_cast, dynamic_cast, reinterpret_cast,还有const_cast.就自己见过的一些C++代码当中,它们的使用其实并不普遍.不少程序员依然乐于去使用C-

  • 深入解析C++中的动态类型转换与静态类型转换运算符

    dynamic_cast 运算符 将操作数 expression 转换成类型为type-id 的对象. 语法 dynamic_cast < type-id > ( expression ) 备注 type-id 必须是一个指针或引用到以前已定义的类类型的引用或"指向 void 的指针".如果 type-id 是指针,则expression 的类型必须是指针,如果 type-id 是引用,则为左值. 有关静态和动态强制转换之间区别的描述,以及各在什么情况下适合使用,请参见 s

  • 基于c++强制类型转换的(总结)详解

    什么是类型转换? 类型转换的含义是通过改变一个变量的类型为别的类型从而改变该变量的表示方式.为了类型转换一个简单对象为另一个对象你会使用传统的类型转换操作符. C与C++的类型转换 C中: 复制代码 代码如下: (T)element 或者 T(element) c++中: 复制代码 代码如下: reinterpret_cast<T*> (expression)dynamic_cast<T*>     (expression)static_cast<T*>      (e

  • 有关C++中类类型转换操作符总结(必看篇)

    实例如下: class SmallInt { public: SmallInt(int i = 0): val(i) { if (i < 0 || i > 255) throw std::out_of_range("Bad SmallInt initializer"); } operator int() const { return val; } private: std::size_t val; }; 转换函数采用如下通用形式: operator type(); type

  • C++中4种类型转换方式 cast操作详解

    Q:什么是C风格转换?什么是static_cast,dynamic_cast以及reinterpret_cast?区别是什么?为什么要注意? A:转换的含义是通过改变一个变量的类型为别的类型从而改变该变量的表示方式.为了类型转换一个简单对象为另一个对象你会使用传统的类型转换操作符.比如,为了转换一个类型为doubole的浮点数的指针到整型:代码:inti;doubled; i=(int)d;或者: i=int(d); 对于具有标准定义转换的简单类型而言工作的很好.然而,这样的转换符也能不分皂白的

  • 解析C++中四种强制类型转换的区别详解

    C++的四种强制类型转换,所以C++不是类型安全的.分别为:static_cast , dynamic_cast , const_cast , reinterpret_cast为什么使用C风格的强制转换可以把想要的任何东西转换成合乎心意的类型.那为什么还需要一个新的C++类型的强制转换呢?新类型的强制转换可以提供更好的控制强制转换过程,允许控制各种不同种类的强制转换.C++中风格是static_cast<type>(content).C++风格的强制转换其他的好处是,它们能更清晰的表明它们要干

  • C++中的类型转换static_cast、dynamic_cast、const_cast和reinterpret_cast总结

    前言 这篇文章总结的是C++中的类型转换,这些小的知识点,有的时候,自己不是很注意,但是在实际开发中确实经常使用的.俗话说的好,不懂自己写的代码的程序员,不是好的程序员:如果一个程序员对于自己写的代码都不懂,只是知道一昧的的去使用,终有一天,你会迷失你自己的. C++中的类型转换分为两种: 1.隐式类型转换: 2.显式类型转换. 而对于隐式变换,就是标准的转换,在很多时候,不经意间就发生了,比如int类型和float类型相加时,int类型就会被隐式的转换位float类型,然后再进行相加运算.而关

  • C++中4种强制类型转换的区别总结

    前言 使用标准C++的类型转换符:static_cast.dynamic_cast.reinterpret_cast和const_cast. const_cast,字面上理解就是去const属性. static_cast,命名上理解是静态类型转换.如int转换成char. dynamic_cast,命名上理解是动态类型转换.如子类和父类之间的多态类型转换. reinterpreter_cast,仅仅重新解释类型,但没有进行二进制的转换. 一.static_cast 用法:static_cast

  • 深入C++四种强制类型转换的总结

    c++中提供了四种新的强制转换分别是:const_cast.dynamic_cast.reinterpret_cast.static_cast.这四种转换类型,每一种都适用于特定的目的:const_cast 一般用于强制取消对象的常量性.它是唯一能够做到这一点的C++风格的强制转型.dynamic_cast 主要用于执行"安全向下转型",也就是说,要确定一个对象是否是一个继承体系中的一个特定类型.它是唯一不能用旧风格语法执行强制转型.reinterpret_cast 是特意用于底层转型

  • 浅谈C++类型转换几种情况

    目录 0. 类型转换的原理 1. 初始化和赋值时进行的转换 2. 以{}方式初始化时进行的转换(C++11新增) 3. 表达式中的转换 4. 传递参数时的转换 5. 强制类型转换 6. 使用auto让编译器自己推断变量类型 0. 类型转换的原理 在进行下面的学习前,我觉得有比较知道不同类型是怎么进行转换的. int a = 777777; //二进制为00000000 01110110 10101101 11110001 short b = a; //b只有2字节,从低位开始截断,只能存1010

  • 浅谈Java的两种多线程实现方式

    本文介绍了浅谈Java的两种多线程实现方式,分享给大家.具有如下: 一.创建多线程的两种方式 Java中,有两种方式可以创建多线程: 1 通过继承Thread类,重写Thread的run()方法,将线程运行的逻辑放在其中 2 通过实现Runnable接口,实例化Thread类 在实际应用中,我们经常用到多线程,如车站的售票系统,车站的各个售票口相当于各个线程.当我们做这个系统的时候可能会想到两种方式来实现,继承Thread类或实现Runnable接口,现在看一下这两种方式实现的两种结果. 程序1

  • 浅谈线程的几种可用状态

    1. 新建( new ):新创建了一个线程对象. 2. 可运行( runnable ):线程对象创建后,其他线程(比如 main 线程)调用了该对象 的 start ()方法.该状态的线程位于可运行线程池中,等待被线程调度选中,获 取 cpu 的使用权 . 3. 运行( running ):可运行状态( runnable )的线程获得了 cpu 时间片( timeslice ) ,执行程序代码. 4. 阻塞( block ):阻塞状态是指线程因为某种原因放弃了 cpu 使用权,也即让出了 cpu

  • 浅谈Java中几种常见的比较器的实现方法

    在Java中经常会涉及到对象数组的排序问题,那么就涉及到对象之间的比较问题. 通常对象之间的比较可以从两个方面去看: 第一个方面:对象的地址是否一样,也就是是否引用自同一个对象.这种方式可以直接使用"=="来完成. 第二个方面:以对象的某一个属性的角度去比较. 从最新的JDK8而言,有三种实现对象比较的方法: 一.覆写Object类的equals()方法: 二.继承Comparable接口,并实现compareTo()方法: 三.定义一个单独的对象比较器,继承自Comparator接口

  • 浅谈Spring的两种事务定义方式

    一.声明式 这种方法不需要对原有的业务做任何修改,通过在XML文件中定义需要拦截方法的匹配即可完成配置,要求是,业务处理中的方法的命名要有规律,比如setXxx,xxxUpdate等等.详细配置如下: <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="

  • 浅谈Spring的两种配置容器

    Spring提供了两种容器类型 SpringIOC容器是一个IOC Service Provider.提供了两种容器类型:BeanFactory和ApplicationContext.Spring的IOC容器是一个提供IOC支持的轻量级容器.除了基本的ioc支持,它作为轻量级容器还提供了IOC之外的支持. BeanFactory BeanFactory是基础类型IOC容器.顾名思义,就是生产Bean的工厂.能够提供完整的IOC服务.没有特殊指定的话,其默认采用延迟初始化策略.只有当客户端对象需要

  • 浅谈js函数三种定义方式 & 四种调用方式 & 调用顺序

    在Javascript定义一个函数一般有如下三种方式: 函数关键字(function)语句: function fnMethodName(x){alert(x);} 函数字面量(Function Literals): var fnMethodName = function(x){alert(x);} Function()构造函数: var fnMethodName = new Function('x','alert(x);') // 由Function构造函数的参数个数可变.最后一个参数写函数体

  • 浅谈vim的四种模式及模式切换

    vim和记事本或WORD不一样,不是一打开后就可以输入文字,此时它处于正常模式. vim一共有4个模式: • 正常模式 (Normal-mode) • 插入模式 (Insert-mode) • 命令模式 (Command-mode) • 可视模式 (Visual-mode) 正常模式 启动vim后默认处于正常模式.不论位于什么模式,按下<Esc>键(有时需要按两下)都会进入正常模式. 插入模式 在正常模式中按下i, I, a, A等键,会进入插入模式.现在只用记住按i键会进行插入模式.在插入模

  • Python入门_浅谈数据结构的4种基本类型

    数据结构:通俗点说,就是储存大量数据的容器.这里主要介绍Python的4种基本数据结构:列表.字典.元组.集合. 格式如下: 列表:list = [val1,val2,val3,val4],用中括号: 字典:dict = {key1:val1,key2:val2},大括号,且每个元素是带有冒号的key与val的对应关系组: 元组:tuple = (val1,val2,val3,val4),小括号: 集合:set = {val1,val2,val3,val4},大括号. 1. 列表: list =

  • 浅谈Python实现2种文件复制的方法

    本文实例主要实现Python中的文件复制操作,有两种方法,具体实现代码如下所示: #coding:utf-8 # 方法1:使用read()和write()模拟实现文件拷贝 # 创建文件hello.txt src = file("hello.txt", "w") li = ["Hello world \n", "Hello China \n"] src.writelines(li) src.close() #把hello.txt

随机推荐