首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 开源 FAQ 第二书店 博文视点 程序员
频道: 研发 数据库 中间件 信息化 视频 .NET Java 游戏 移动 服务: 人才 外包 培训
    图书品种:235680
       
热门搜索: ASP.NET Ajax Spring Hibernate Java

首先,介绍一些术语。运算(例如算术运算)是由运算符定义的,例如,+用于相加,*用于相乘。运算符操作的数值称为操作数,在表达式2*3中,操作数是2和3。

乘号运算符需要两个操作数,所以称为二元运算符。其他一些运算符只需要一个操作数,称为一元运算符。一元运算符的一个例子是–2中的减号。减号可作用于一个操作数,值2,改变它的符号。表达式4-2中的二元减号运算符与此相反,它作用于两个操作数4和2。

2.2.1 字面量

在C++中,任一类型的固定值,例如42,2.71828或"Mark Twain"都称为字面量。第1章在屏幕上输出文本字符串时,使用了“字符串字面量”这一术语,它表示用一对双引号括起来的一系列字符所定义的常量。"Mark Twain"就是一个字符串字面量。下面要研究数值常量的字面量类型。这些普通数字我们每天都会遇到:鞋子的尺寸、铅的沸点,站在针尖上的天使个数等所有已定义好的数字。

在C++中,可以使用两大类数值常量:

● 整型数字面量:即不包含小数点的整数。

● 浮点字面量(通常称为浮点数):包含小数点或指数或两者都包含的小数(稍后介绍指数)。

当所处理的是一个整型数时,就应使用整型数字面量,例如球队中的队员数或一本书的页数。在数值不是整型数时,应使用浮点字面量,例如圆的周长除以其直径,或英镑与美元的汇率。

在处理非常小或非常大的数值时,也应使用浮点数,例如电子的重量、银河的直径或蝙蝠飞行的速度。使用术语“浮点数”的原因是这些数值是用固定位数的数字和小数点表示的,其中小数点可以根据数字的固定设置左右移动。

小数点浮动

看看下面两个数字:

0.00000000000000000000000001234567 1.234567×10-21

12345670000000000000000000000000.0 1.234567×10+26

这两个数值都有7位数,但它们是完全不同的数值。第一个数字非常小,第二个数字非常大。左边每个数字的浮点数表示方式显示在右边。数字乘以10的幂会在基本数1.234567中移动小数点。使小数点的灵活定位允许用最有限的内存表示和存储范围非常大的数值,包括非常小的数值和非常大的数值。

下面首先介绍如何使用整型数,因为整型数是两者中比较简单的类型。然后讨论浮点数。

2.2.2 整型字面量

可以用非常直接的方式表示整型字面量。下面是一些例子:

–123 +123 123 22333

其中,前两个例子中的“+”和“–”号是前面提及的一元运算符。在第二个例子中,可以省略“+”,因为这是默认的,但为了使该数值的含义更清晰,加上“+”也不会出问题。字面量+123与123是相同的。第4个例子在一般情况下写为22,333,但在整型字面量中不能使用逗号。如果使用了逗号,编译器就会把该数值当做用逗号分隔开的两个数值。

也不能使用老式的整数值。举一个极端的例子,系统不接受有100位的整数。整型字面量是有上限和下限的,这是由存储每种类型的整数值的内存量决定的。本章在后面介绍整型变量时将讨论这个问题,并论述指定整型字面量的更多选项。

当然,可以把整型字面量写成小数值,在计算机中这些值将存储为二进制数值。在编程时理解二进制是非常重要的,为了防止读者对二进制数字的工作方式有误解,附录E作了简要的介绍。如果对二进制数和16进制数不理解,最好先浏览一下附录E,再继续下一节的内容。

1. 十六进制的整型字面量

在前面的例子中,整型字面量都是十进制整数,也可以把整数表示为十六进制数。为了说明某个数是十六进制,应在该数值的前面加上0x或0X前缀。如果某个数是0x999,就表示这是一个十六进制数,而999就是一个十进制数,它们是完全不同的。下面的例子把整型字面量写为十六进制数值。如表2-1所示。

表2-1 十六进制值及对应的十进制值

十六进制值

对应的十进制表示

十 进 制 值

0x1AF

1×162+10×161+15×160

431

0x123

1×162+2×161+3×160

291

0xA

10×160

10

0xCAD

12×162+10×161+13×160

3245

0xFF

15×161+15×160

255

第1章介绍了在定义字符的转义序列中使用的十六进制表示法。现在讨论的是如何定义整数。本章后面还将讨论定义字符字面量。

十六进制的整型字面量主要在定义位的特定模式时使用。因为每个十六进制位都对应二进制值的4位,所以很容易把位的特定模式表达为十六进制的字面量。下一章将深入探讨这个问题。

2. 八进制的整型字面量

还可以把整数表示为八进制值,即以8为基数。把数值表示为八进制时,要给它加上一个前导0。表2-2列出了八进制值的一些例子。

表2-2 八进制值及对应的十进制值

八 进 制 值

对应的十进制整数

0123

83

077

63

010101

4161

当然,八进制值的数字只能是0~7。目前八进制值使用得不多,它在C++中依旧存在主要是其历史原因:以前计算机处理的字的长度是3的倍数。但是,知道存在八进制是很重要的,因为如果不小心使用了一个带有前导0的十进制数,计算机就会把它解释为八进制值。

注意:

不要给十进制的整数值加上前导0。编译器会把这种数值解释为八进制(基数为8),因此表示为065的值就等价于十进制表示法中的53。

从编译器的角度来看,它并不在意用户表示整数值时使用什么进制,该数值最终都会在计算机中存储为一个二进制数。在表示整数时使用什么方式只取决于是否方便。可以把整数15表示为15,0xF或017,这些数值都将存储为同一个二进制值,所以应选择使用适合于当前环境的某种进制。

2.2.3 整数的算术运算

对整数可以进行的基本算术运算如表2-3所示。

表2-3 基本的算术运算

运 算 符

运 算

+

*

/

取模(除法运算后的余数)

表2-2中的运算符的工作方式与我们期望的大致相同,注意它们都是二元运算符。但是,除法运算略微特殊一点,下面详细说明。整数运算总是得到整数结果,例如,表达式11/4的结果不是2.75,而是2。“整数除法”返回被除数和除数相除后的整数部分,舍弃了余数部分。在C++标准看来,除以0的结果是不确定的,但特定的实现方式通常定义了其结果,在某些情况下,会提供一种响应的编程方式,所以读者应查阅产品的文档说明。

图2-1说明了除法和取模的不同结果。

图2-1 比较除法和取模运算符

取模运算符%有时称为取余运算符,它是对除法运算符的补充,它提供了一种在整数除法运算后获取其余数的方式。表达式11%4的结果是3,这是11除以4后的余数。取模运算符的一个或两个操作数是负数时,余数的符号由所使用的C++实现方式来确定,因此不同的系统会有不同的结果。使用取模运算符肯定要涉及相除,所以在右操作数为0时,其结果是不确定的。

下面用一个例子来说明算术运算符的使用。

程序示例2.1—— 整数的算术运算

下面编写一个程序,输出一个涉及整数的杂项表达式集合的结果,以此来说明算术运算符的运算方式。

// Program 2.1 – Calculating with integer constants

#include <iostream> //For output to the screen

using std::cout;

using std::endl;

int main() {

cout << 10 + 20 <<endl; //Output is 30

cout << 10 - 5 <<endl; //Output is 5

cout << 10 - 20 <<endl; //Output is -10

cout << 10 * 20 <<endl; //Output is 200

cout << 10 / 3 <<endl; //Output is 3

cout << 10 % 3 <<endl; //Output is 1

cout << 10 % -3 <<endl; //Output is 1

cout << -10 % 3 <<endl; //Output is -1

cout << -10 % -3 <<endl; //Output is -1

cout << 10 + 20 / 10–5 <<endl; //Output is 7

cout << (10 + 20)/(10–5) <<endl; //Output is 6

cout << 10 + 20/(10–5) <<endl; //Output is 14

cout << (10 + 20)/10–5 <<endl; //Output is –2

cout <<4*5/3%4 + 7/3 <<endl; //Output is 4

return 0; //End the program

}

该例子的输出如下:

30

5

–10

200

3

1

1

-1

-1

7

6

14

–2

4

这种锯齿状的输出格式并不是很好。而这就是默认情况下整数的输出结果。稍后就解释如何使其格式更悦目。下面先讨论这个例子中有趣的地方。

例子的说明

每个语句都计算了一个算术表达式,并在屏幕上输出结果,之后用一个换行符把光标移到下一行的开头。这里的所有算术表达式都是常量表达式,因为它们的值在程序执行前就已由编译器确定了。

前5个语句都很简单,它们之所以会输出那些结果的原因也很明显:

cout << 10+20 <<endl; //Output is 30

cout << 10–5 <<endl; //Output is 5

cout << 10–20 <<endl; //Output is -10

cout << 10*20 <<endl; //Output is 200

cout << 10/3 <<endl; //Output is 3

cout << 10%3 <<endl; //Output is 1

因为整数运算将生成整数结果,所以表达式10/3的结果就是3,因为10除以3的整数部分是3,余数部分1则被舍弃。

下面四行代码说明取模运算符的操作:

cout << 10 % 3 <<endl; //Output is 1

cout << 10 % -3 <<endl; //Output is 1

cout << -10 % 3 <<endl; //Output is -1

cout << -10 % -3 <<endl; //Output is -1

这是取模运算符的操作数符号的所有组合。第一行代码中的两个操作数都是正的,其输出是在任何系统上运行该代码时惟一一个相同的。其他三行代码的结果可能有不同的符号。

以下4个语句说明了括号的作用:

cout << 10+20/10–5 <<endl; //Output is 7

cout << (10+20)/(10–5) <<endl; //Output is 6

cout << 10+20/(10–5) <<endl; //Output is 14

cout << (10+20)/10–5 <<endl; //Output is -2

括号重写了表达式中运算符的执行顺序。括号中的表达式总是先执行,如果括号是嵌套的,就先执行最内层括号中的表达式,再执行外层括号中的表达式。

在涉及几个不同运算符的表达式中,运算符的执行顺序由运算符的优先权来决定。赋予运算符的优先权称为其优先级。对于前面用于整数算术运算的运算符来说,运算符“*”、“/”和“%”构成一个优先级组,其优先级要高于运算符“+”和“–”,而运算符“+”和“–”又构成了另一个优先级组。运算符“*”、“/”和“%”的优先级总是高于“+”和“–”。给定组中的运算符,例如“+”和“–”,有相同的优先级。本例中最后一个输出语句说明了优先级如何决定运算符的执行顺序:

cout << 4*5/3%4 + 7/3 <<endl; //Output is 4

“+”运算符的优先级要低于其他运算符,所以相加运算最后执行。也就是说,两个子表达式4 * 5 / 3 % 4和7 / 3的值应先计算。子表达式4 * 5 / 3 % 4中的运算符具有相同的优先级,所以其执行顺序由运算符的相关性来确定。运算符组的相关性可以是“左”或“右”。具有“左”相关性的运算符会首先绑定到运算符左边的操作数上,所以这种运算符的执行顺序就是从左到右。下面用例子来说明。

在表达式4 * 5 / 3 % 4中,每个运算符都是左相关,也就是说,每个运算符左边的操作数就是该运算符左边的所有内容。例如,乘号*的左操作数是4,除号/的左操作数是4*5,取模%运算符的左操作数是4*5/3,因此该表达式应计算为((4 * 5) / 3) % 4,即从左向右计算。

在表达式中,运算符的相关性决定了同一组中运算符的执行顺序,但这与操作数没有任何关系。例如,在表达式4 * 5 / 3 % 4 + 7 / 3中,并没有指定子表达式4 * 5 / 3 % 4要在表达式7 / 3之前计算,或者表达式7 / 3要在表达式4 * 5 / 3 % 4之前计算。先计算哪一个表达式都是可以的,这取决于编译器,因为计算的结果是没有区别的。在本例中也是如此:先计算相加的哪一个操作数并不重要,但其所在的环境可能会有差别,稍后在编程过程中将讨论这一点。

2.2.4 运算符的优先级和相关性

在C++中,几乎所有的运算符组都具有左相关性,所以大多数涉及优先级相同的运算符的表达式都是从左到右计算。惟一一个右相关性的运算符是前面已提及的一元运算符和赋值运算符(稍后介绍)。

下面把整数算术运算符的优先级和相关性列在表2-4中,以表示算术表达式中的执行顺序。

表2-4 整数算术运算符的优先级和相关性

运 算 符

相 关 性

一元 + –

* / %

+–

表2-4中的每一行都是一个优先级相同的运算符组。组的排列也是按顺序的,优先级最高的运算符组放在第一行,优先级最低的运算符组放在最后一行。由于这个表只包含三行,所以非常简单,但后面还将介绍更多的运算符,在学习C++的过程中会在这个表中添加更多的行。

注意:

C++标准没有直接定义运算符的优先级,但这可以根据标准中定义的语法规则来确定。在大多数情况下,很容易从运算符的优先级上看出给定表达式的执行顺序,而不是从语法规则中看出。所以本书在介绍运算符时都会提及其优先级。

如果要查看C++中所有运算符的优先级表,可参阅附录D。

程序示例2.1A—— 美化输出结果的外观

前面例子的输出结果肯定是正确的,尽管其看起来并不像。出现“锯齿状”效果的原因是每个整数的输出都放在一个字段宽度中,也就是说,用对应个数的字符来容纳该数值。下面把每个数据项的字段宽度设置为我们选择的值,如下所示:

//Program 2.1A – Producing neat output

#include <iostream> //For output to the screen

#include <iomanip> //For manipulators

using std::cout;

using std::endl;

using std::setw;

int main() {

cout<<setw(10)<<10+20 <<endl; //Output is 30

cout<<setw(10)<<10-5 <<endl; //Output is 5

cout<<setw(10)<<10-20 <<endl; //Output is–10

cout<<setw(10)<<10*20 <<endl; //Output is 200

cout<<setw(10)<<10/3 <<endl; //Output is 3

cout<<setw(10)<<10%-3 <<endl; //Output is 1

cout<<setw(10)<<-10%3 <<endl; //Output is 1

cout<<setw(10)<<-10%-3 <<endl; //Output is 1

cout<<setw(10)<<10%3 <<endl; //Output is 1

cout<<setw(10)<<10+20/10-5 <<endl; //Output is 7

cout<<setw(10)<<(10+20)/(10-5) <<endl; //Output is 6

cout<<setw(10)<<10+20/(10-5) <<endl; //Output is 14

cout<<setw(10)<<(10+20)/10-5 <<endl; //Output is –2

cout<<setw(10)<<4*5/3%4+7/3 <<endl; //Output is 4

return 0; //End the program

}

这样,输出结果应如下所示:

30

5

-10

200

3

1

1

-1

-1

7

6

14

-2

4

例子的说明

这看起来就整齐多了。通过改变输出语句,就可以得到这种整洁的格式。输出结果中所显示的每个值都在前面加上setw(10),如第一个语句所示:

cout<<setw(10)<<10+20 <<endl; //Output is 30

我们将setw()称为操纵程序(manipulator),因为它允许操纵或控制输出的外观。操纵程序不输出任何内容,只是修改输出过程。它的作用是把下一个要输出的值的字段宽度设置为括号中指定的字符数,在本例中就是10。使用setw()设置的字段宽度只应用于下一个写入cout的值。后续的值会以默认格式显示。

还需要加上另一个#include语句来包含标准头文件<iomanip>,以使setw()操纵程序可以在程序中使用。本例还添加了一个using指令,以使用未限定的setw名称。后面还将在其他例子中使用其他操纵程序。另外,用户也可以用其他字段宽度进行试验,看看其效果如何。

查看所有评论(0)条】

最近评论



正在载入评论列表...
热点评论