第三章 处理数据
本章内容包括:
- C++变量的命名规则。
- C++内置的整型——unsigned long、long、unsigned、int、int、unsigned short、short、char、unsigned char、signed char和bool。
- C++11新增的整型:unsigned long long和long long。
- 表示各种整型的系统限制的climits文件。
- 各种整型的数字字面值(常量)。
- 使用const限定符来创建符号常量。
- C++内置的浮点类型:float、double和long double。
- 表示各种浮点类型的系统限制的cfloat文件。
- 各种浮点类型的数字字面值。
- C++的算术运算符。
- 自动类型转换。
- 强制类型转换。
● 内置的C++类型分两组:基本类型和复合类型
。基本类型,即整数和浮点数。在基本类型的基础上创建的复合类型,包括数组、字符串、指针和结构。
● 必须遵循几种简单的C++命名规则
:
(1)在名称中只能使用字母字符、数字和下划线。
(2)名称的第一个字符不能是数字。
(3)区分大写字符和小写字符。
(4)不能将C++关键字用作名称。以两个下划线或下划线和大写字母打头的名称被保留给实现(编译器及其使用的资源)使用。以一个下划线开头的名称被保留给实现,用作全局标识符。
(5)C++对于名称的长度没有限制,名称中的所有字符都有意义,但有些平台有长度限制。
● C++提供了一种灵活的标准,它确保了最小长度
(从C语言借鉴而来),如下所示:
(1)short至少16位;
(2)int至少与short一样长;
(3)long至少32位,且至少与int一样长;
(4)long long至少64位,且至少与long一样长。
● 符号常量,预处理器方式。
#define INT_MAX 32767
#define和#include一样,也是一个预处理器编译指令,也可以使用#define来定义自己的符号常量,但是#define编译指令是C语言遗留下来的,C++有一种更好的创建符号常量的方法(使用关键字const),所以不会经常使用#define。然而,有些头文件,尤其是那些被设计成可用于C和C++中的头文件,必须使用#define。
● 使用const的时候,应在声明中对const进行初始化。const比#define好
,首先,它能够明确指定类型。其次,可以使用C++的作用域规则将定义限制在特定的函数或文件中(作用域规则描述了名称在各种模块中的可知程序)。第三,可以将const用于更复杂的类型。
● C++提供了大量的整型,应使用哪种类型呢?通常,int被设置为对目标计算机而言最为“自然”的长度。自然长度(natural size)
指的是计算机处理起来效率最高的长度。如果没有非常有说服力的理由来选择其他类型,则应使用int。
● 整型字面值(常量)是显式地书写的常量。与C相同,C++能够以三种不同的计数方式来书写整数:基数为10,基数为8(老式UNIX版本)和基数为16(硬件黑客的最爱)。基数为10,第一位为1-9;基数为8,第一位是0,第二位为1-7;基数为16,前两位为0x或0X。头文件iostream提供了控制符dec、hex和oct
,分别用于指示cout以十进制、十六进制和八进制格式显示整数。
● 后缀是放在数字常量后面的字母,用于表示类型。
类型 | 缩写 |
---|---|
long、long double | l或L |
unsigned int | u或U |
unsigned long | ul(可任何一种顺序、大写小写均可) |
long long | ll或LL |
unsigned long long | ull或Ull或uLL或ULL |
float | f或F |
● 任何数字值和指针值都可以被隐式转换(即不用显示强制转换)为bool值。任何非零值都被转换为true,而零被转换为false。
● C++有两种书写浮点数的方式
。第一种是使用常用的标准小数点表示法,第二种表示浮点值的方法叫做E表示法,其外观是像这样的:3.45E6,这指的是3.45与1000000相乘的结果,E6指的是10的6次方,即1后面6个0,6被称为指数,3.45被称为尾数。
● C++也有3种浮点类型:float、double和long double。这些类型是按它们可以表示的有效位数和允许的指数最小范围来描述的。有效位(significant figure)是数字中有意义的位。可以从头文件cfloat或float.h中找到系统的限制。
● ostream方法cout.setf(ios_base::fixed, ios_base::floatfield)
,这种调用迫使输出使用定点表示法,以便更好地了解精度,它防止程序把较大的值切换为E表示法,并使程序显示到小数点后6位。参数ios_base::fixed和ios_base::floatfield是通过包含iostream来提供的常量。通常cout会删除结尾的零。
● 与整数相比,浮点数有两大优点
。首先,它们可以表示整数之间的值。其次,由于有缩放因子,它们可以表示的范围大得多。另一方面,浮点运算的速度通常比整数运算慢,且精度将降低。
● 求模运算符,余数,两个操作数必须都是整数,将该运算符用于浮点数将导致编译错误。如果其中一个是负数,则结果的符号满足如下规则:(a/b)*b + a%b = a
。它与整数除法相结合,尤其适用于解决要求将一个量分成不同的整数单元的问题,例如将英寸转换成英尺和英寸,或者将美元装换为元、角、分、厘。
● 当两个运算符的优先级相同时,C++将看操作数的结合性(associativity)是从左到右,还是从右到左。从左到右的结合意味着如果两个优先级相同的运算被同事用于同一个操作数,则首先应用左侧的运算符。从右到左的结合性则首先应用右侧的运算符。
● C++自动执行很多类型转换
:将一种算数类型的值赋给另一种算术类型的变量时,C++将对值进行转换;表达式中包含不同的类型时,C++将对值进行转换;将参数传递给函数时,C++将对值进行转换。下面是这些规则的详细介绍:
(1)
初始化和赋值进行的转换
(2)
以{}方式初始化时进行转换(C++11)
C++11将使用大括号的初始化称为列表初始化(list-initialization),因为这种初始化常用于给复杂的数据类型提供值列表。它对类型转换的要求更严格,具体来说,列表初始化不允许缩窄(narrowing),即变量的类型可能无法表示赋给它的值。
(3)
表达式中的转换
当同一个表达式中包含两种不同的算术类型时,C++将执行两种自动转换:首先,一些类型在出现时便会自动转换;其次,有些类型在与其他类型同时出现在表达式中时将被转换。
(4)
自动转换
在计算表达式时,C++将bool、char、unsigned char、signed char和short值转换为int。具体来说,true被转换为1,false被转换为0。这些转换被称为整型提升(integral promotion)。
编译器通过校验表来确定在算术表达式中执行的转换,下面是C++11版本的校验表,编译器将依次查阅该列表:
- 如果有一个操作数的类型是long double,则将另一个操作数转换为long double。
- 否则,如果有一个操作数的类型是double,则将另一个操作数转换为double。
- 否则,如果有一个操作数的类型是float,则将另一个操作数转换为float。 否则,说明操作数都是整型,因此执行整型提升。
- 在这种情况下,如果两个操作数都是有符号或无符号的,且其中一个操作数的级别比另一个低,则转换为级别高的类型。
- 如果有一个操作数为有符号的,另一个操作数为无符号的,且无符号操作数的级别比有符号操作数高,则将有符号操作数转换为无符号操作数所属的类型。
- 否则,如果有符号类型可表示无符号类型的所有可能取值,则将无符号操作数转换为有符号操作所属的类型。
- 否则,将两个操作数都转换为有符号类型的无符号版本。
(5)
传递参数时的转换
传递参数时的类型转换通常由C++函数原型控制,然而,也可以取消原型对参数传递的控制,尽管这样做并不明智。这种情况下,C++对char和double类型(signed和unsigned)应用整型提升,将float参数提升为double。
(6)
强制类型转换
强制类型转换的格式有两种:
(typeName) value //converts value to typeName type
typeName (value) //converts value to typeName type
第一种格式来自C语言,第二种格式是纯粹的C++,新格式的想法是,要让强制类型转换就像是函数调用。强制类型转换不会修改变量本身,而是创建一个新的、执行类型的值,可以在表达式中使用这个值。
● C++11中的auto声明
C++11新增了一个工具,让编译器能够根据初始值的类型推断变量的类型。在初始化声明中,如果使用了关键字auto,而不指定变量的类型,编译器将把变量的类型设置成与初始值相同。
处理复杂类型,如标准模块库(STL)中的类型时,自动类型推断的优势才能显现出来。
对于C++98代码:
std::vector<double> scores;
std::vector<double>::iterator pv = scores.begin();
C++11允许将其重写为下面这样:
std::vector<double> scores;
auot pv = scores.begin();