C语言的类型转换
赋值转换
将一种类型的值赋给另一种类型的变量,此时值会转变为接收变量的类型
1 | int ival = 3.14; //3.14被截断为3 |
当把一个超出其范围的值赋给一个指定类型的对象时,不同的系统有不同的操作。将int类型的数赋值给short类型时,大多数系统将int的低字节赋值,高字节舍去:
1 | short a = 0x1111FFFF; //a的值为0xFFFF |
当把一个取值范围小的值赋给取值范围大的值,会根据符号位自动补值:
1 | char a = 0xe0; |
表达式转换
当同一个表达式中出现不同类型的量时,会根据不同的情况对操作数进行自动转换,这些转换可分为“整数提升”和“运算时的转换”:
- 整数提升:表达式计算时,bool、char、unsigned char、short都会自动转换成int型,bool值类型中true转为1,false转为0;
- 运算时转换:运算涉及两种类型时,较小的类型(表达力低)会转换为较大的类型(表达力高),表达力从低到高的排序为“int➡unsigned int➡long➡unsigned long➡fload➡double➡long double”;
表达式转换时long和unsigned int的转换需要注意,32位机器上long和int通常都是一个字长,所以表达式中包含unsigned int和long两种类型时,这俩统一转换为unsigend long;
表达式中出现同类型的signed和unsigned数时,统一转换为unsigned,只是把符号位当作数值位计算。比如int型的-1会转换为unsigned int的\(2^{32}-1\),这就是常说的溢出了。要注意此时内存中的内容并没有改变,只是解释不一样。
显式转换
显示转换也称为强制类型转换,格式为“(类型说明符)(表达式)”,比如double f = double(1)/double(2);。基本类型的指针之间不含隐式转换(void*除外),都需要显示转换。
隐式转换
把一个表达式传递给一个函数调用、从函数中返回一个表达式会发生隐式类型转换.
1 | double f = 1/2; |
C++的类型转换
const_case
用于转换指针或引用,去掉类型的const属性。
这几种类型转换,只有const_cast可以将const性质转换掉,其余都不行。相应的,除了添加或删除const属性,const_cast也无法执行其他的类型转换任务。
1 | //const_case使用 |
reinterpret_cast
这是一种很危险的类型转换。既不检查指向的内容,也不检查指针类型本身,只是做了类型的重新解释。reinterpret_cast需要保证转换前后的类型所占用的内存大小一致,否则将引发编译时错误。
虽然危险,但工程中的使用常见还是比较广泛,比如void*和其他类型的转换,遇到这种场景最好使用reinterpret_cast而不是C语言的强制类型转换,因为C语言的强制转换不做任何的检查。
1 | //reinterpret_cast使用 |
static_case和dynamic_cast
static_cast用于基本的类型转换(这种方式就是类似于C语言的类型转换方式)。仅当类型之间可隐式转换时,static_cast的转换才是合法的,否则将出错,比如基本类型的指针之间不含有隐式转换,那么使用static_cast进行显式转换将编译错误。
static_cast也可以用于有继承关系类对象和类指针之间的转换,但需要由程序员来确保转换是安全的,它不会产生动态转换的类型安全检查的开销,因为类型检查不是编译器能检测出来的,必须要等到运行时才能动态检查。
dynamic_cast是为了弥补static_cast的不足,可以做类型的检查。类型检查需要运行时类型信息,而这个信息存储在类的虚函数表中,因此它只能用于含有虚函数的类,必须用于多态体系中,用于类层次间的向上和向下转化;向上转化时和static_cast效果相同,向下转化时,如果是非法的对于指针返回NULL,引用抛出bad_cast异常(向上转化:子类转换为父类;向下转化:父类转化为子类。子类转化为父类比较安全,但父类转化为子类不安全,因为子类一定有父类的属性,但父类未必有子类的属性)。
dynamic_cast只能用于类的指针、类的引用或void*。
1 | //static_cast 和 dynamic_cast |