C++自动执行很多类型转换:
- 将一种算术类型的值赋给另一种算术类型的变量时,C++将对值进行转换;
- 表达式中包含不同类型时,C++将对值经行转换;
- 将参数传递给函数时,C++将对值经行转换。
1. 初始化和赋值进行的转换
C++允许将一种类型的值赋给另一种类型变量。这样做时,值将被转换为接收变量的类型。
例如,假设so_long的类型为long,thirty的类型为short,而程序中包含这样的语句:
so_long = thirty; //assigning a short to along
则进行赋值时,程序将thirty的值(通常为16位)扩展为long值(通常为32位)。扩展后将得到一个新值,这个值被存储在so_long中,而thirty的内容不变。
将一个值赋给值取值更大的类型通常不会导致什么问题。例如,将short值赋给long变量并不会改变这个值,只是占用的字节更多而已。然而,将一个很大的long值(如2111222333)赋给float变量将降低精度。因为float只有6位有效数字,因此这个值被四舍五入为2.11122E9。因此,有些转换是安全的,有些则会带来麻烦。如下表,列出了一些可能出现的转换问题。
转换 | 潜在的问题 |
将较大的浮点类型转换为较小的浮点类型,如将double转换为float | 精度(有效位)降低,值可能超出目标类型的取值范围,在这种情况下,结果将不确定 |
将浮点类型转换为整型 | 小数部分丢失,原来的值可能超出目标类型的取值范围,在这种情况下,结果将不确定 |
将较大的整型转换为较小的整型,如将long转换为short | 原来的值可能超出目标类型的取值范围,通常只复制右边的字节 |
将0赋给bool变量时,将被转换为false;而非零值将被转换为true。
将浮点型赋给整型将导致两个问题。首先,将浮点值转换为整型会将数字截短(除掉小数部分)。其次,float值对int变量来说可能太大了。如下代码:
int guess(3.9832); //double converted to int
int debt = 7.2E12; //result not define in C++
输出为:
guess = 3
debt = 1634811904
对于debt变量,不同编译器显示的值也可能不同。
2. 以{}方式初始化时进行的转换(C++11)
C++11将使用大括号的初始化称为列表初始化,因为这种初始化常用于给复杂的数据类型提供值列表。列表初始化不允许缩窄(narrowing),即变量的类型可能无法表示赋给它的值。
const int code = 66;
int x = 66;
char c1{31325}; //narrowing,not allowed
char c2 = {66}; //allowed because char can hold 66
char c3 {code}; //ditto
char c4= {x}; //not allowed,x is not constant
x = 31325;
char c5 = x; //allowed by this form of initialization
在上述代码中,初始化c4时,知道x的值为66,但在编译器看来,x是一个变量,其值可能很大。编译器不会跟踪下述阶段可能发生的情况:从x被初始化到它被用来初始化c4。
3. 表达式转换
当同一个表达式中包含两种不同的算术类型时,C++将执行两种自动转换:首先,一些类型在出现时便会自动转换;其次,有些类型在与其他类型同时出现在表达式中时将被转换。
在计算表达式时,C++将bool、char、unsigned char、signed char和short值转换为int。具体说,ture被转换为1,false被转换为0。这些转换被称为整型提升。
当运算涉及两种类型时,较小的类型将被转换为较大的类型。以下是C++11版本的校验表,编译器将依次查阅该表。
(1)如果有一个操作数的类型是long double,则将另一个操作数转换为long double。
(2)否则,如果有一个操作数的类型是double,则将另一个操作数转换为double。
(3)否则,如果有一个操作数的类型是float,则将另一个操作数转换为float。
(4)否则,说明操作数都是整型,因此执行整数提升,
(5)在这种情况下,如果两个操作数都是有符号或无符号的,且其中一个操作数的级别比另一个低,则转换为级别高的类型。
(6)如果一个操作数为有符号的,另一个操作数为无符号的,且无符号操作数的级别比有符号操作数高,则将有符号操作数转换为无符号操作数所属的类型。
(7)否则,如果有符号类型可表示无符号的所有可能取值,则将无符号操作数转换为有符号操作数所属的类型。
(8)否则,将两个操作数都转换为有符号类型的无符号版本。
4. 强制类型转换
强制类型转换的通用格式如下:
(typeName) value //converts value to typeName type
typeName (value) //converts value to typeName type
注:本文是本人学习《C++ Primer Plus》的笔记。