C++的运算符和表达式
运算符是施加在数据上的重要操作,变量、常量通过操作符组合成C++的表达式,构成了C++程序的基本要素。本节将介绍C++语言中基本运算符和表达式。
2.4.1 C++中的基本运算符
运算是对数据的加工过程,而标识不同运算的符号称职运算符,参与运算的数据称为操作数。表2.3列出了C++中的基本运算符、其优先级及对操作数的结合性。
优先级
运算符
运算顺序
功能
17
17
,:
,:
从右向左结合从左向右结合
全局范围符(单目)
类范围符(双目)
16
16
16
16
16
→,.
[ ]
( )
( )
sizeof
从左向右结合从左向右结合从左向右结合从左向右结合从左向右结合
成员选择符数组下标符函数调用类型结构取类型存储大小
15
15
15
15
15
15
15
++,--
~

+,-
*,&
()
new,delete
从右向左结合从右向左结合从右向左结合从右向左结合从右向左结合从右向左结合从右向左结合
自增,自减按位反逻辑否单目加,单目减指针操作,取址类型转换动态空间管理
14
->*,.*
从左向右结合
成员指针选择
13
*,/,%
从左向右结合
乘法类运算
12
+,-
从左向右结合
加法类运算
11
<<,>>
从左向右结合
移位运算
10
<,<=>,>=
从左向右结合
关系比较
9
= =,!=
从左向右结合
等值,不等值比较
8
&
从左向右结合
按位与
7
^
从左向右结合
按位异或
6
|
从左向右结合
按位或
5
&&
从左向右结合
逻辑与
4
||
从左向右结合
逻辑或
3
?:
从左向右结合
条件操作符
2
=,*=,/=,%=,+=,—=,
<<=,>>=,&=,|=,^=
从右向左结合从右向左结合
赋值符
1
,
从左向右结合
逗号表达式
注:优先级相同的运算符,其执行顺序由该运算符在语句中的位置先后决定。
根据参与运算的操作数的类型不同,运算符可以分为单目运算符(1个操作数)、双目运算符(2个操作数)、三目运算符(3个操作数)。有一些运算符既可以是单目的,也可以是双目的,根据赋予该运算符的操作数的不同,运算符具有不同的功能。
例如,*pFile; var1*var2;
运算符的优先级和数学运算中的优先级意义相同,它决定了一个操作符在表达式的运算顺序,优先级越高,运算次序越靠前。而结合性则决定一个操作符对其操作数的运算顺序。如果一个操作符对其操作数的操作运算是自左向右执行的,则称该操作符是右结合的;反之如果一个操作符对其操作数的操作运算是自右向左执行的,则称该操作符是左结合实际的。
根据操作符表示的运算的性质不同,可以将C++中的操作符分为算术运算、关系运算符、逻辑运算符、赋值运算符、条件运算符、自增自减运算符、位运算符和sizeof运算符等。下面分别进行讨论。
1、算术运算符
表2.4列出了C++中的算术运算符。
表2.4 C++中的算术运算符运算符
运算操作
例子
-
取负(单目)
-var
+
加法
var1+var2
-
减法(双目)
var1-var2
*
乘法
var1*var2
/
除法
var1/var2
%
取模(余)
var1%var2
对于单目运算符-,其返回值的数据类型与操作数的数据类型相同.对于双目运算符+、-、*和/,若其两个操作数的数据类型相同,则返回值的数据类型与操作数的数据类型相同;若两操作数的数据类型不同,则返回值的数据类型与字长较长的操作数的数据类型相同。
注意:两个整数相除的结果仍然是整数。若被除数不能被除数整除,则相除的结果将被取整,其小数部分将被略去。
例如:34/7; 12.5%3(非法) 35%7
在某些情况下,算术运算表达式会产生某些问题,计算的结果将给出错误或没有定义的数值,这些情况称为运算异常。对不同的运算异常,将产生不同的后果。在C++中,除数为零和实数溢出被视为一个严重的错误而导致程序运行的异常终止。而整数溢出则不被认为是一个错误(尽管其运算结果有可能与预期值不同)。因此,在一些与硬件打交道的低级程序中利用整数溢出查看设备的状态位等。
2、关系运算符表2.5列出了C++中的关系运算符,它们都是双目运算符。关系运算符的返回值只有逻辑真和逻辑假两种。当两个操作数满足关系运算符所要求的比较关系时,返回整型数1(真);否则返回整型数0(假)。
表2.5 C++中的关系运算符运算符
运算操作
使用例子
<
小于
var1<var2
<=
小于等于
var2<=var2
>
大于
var2>var2
>=
大于等于
var2>=var2
= =
等于
var2= =var2
!=
不等于
var2!=var2
例如:var1=85;var2=91;
var3=(var1<var2)+6; //结果为7
注意:(1)、关系运算符的两个操作数可以是任何基本数据类型。
(2)、在进行相等及不相等关系关系运算时,除了两个操作数都有是整型数之外,由于计算机的存储方式及计算误差,运算结果常常会与预期结果相反。因此,在比较两个实数(浮点数或双精度型)相等或不等时,常用判断这两个操作数的差值的绝对值小于或大于某一给定的小数值来代替(可靠性高一些)。
3、逻辑运算符表2.6列出了C++中的逻辑运算符,逻辑运算符用来表示操作数的逻辑关系,其运算结果是整型数1或0。逻辑运算的结果也可以作为一个整型数用在算术运算中。
表2.6 C++中的逻辑运算符运算符
运算操作
使用例子
!
逻辑反
!expr
&&
逻辑与
expr1&&expr2
||
逻辑或
expr1||expr2
注意:在C++中,0被看作逻辑假,而其他的非零值(任意基本数据类型)均被视为逻辑真。
4、赋值运算符赋值运算符“=”将左边的变量值或表达式的值赋给左边的变量,其结果是将一个新的数值存放在左操作数所占用的内存单元中。
赋值运算也有返回值,该返回值的数值是右操作数的数值,而其数据类型则与左操作数的数据类型相同。同时,赋值运算的运算次序是从右到左进行的。所以采用多个赋值运算符可以将多个操作数连接起来,其运算结果是将表达式最右端的操作数的值赋给其左边的各个操作数。
例如:var1=var2=var3=var4=21;
赋值操作符可以与某些算术操作符、关系操作符或位操作符进行复合,产生一个新的双目操作符,其功能是将该操作符的左、右操作数分别作为相应的算术操作符、关系操作符或位操作符的左、右操作数进行相应的算术、比较或位操作,再将运算的结果赋给复合操作符的左操作数。在C++中可以使用的10种复合操作符,具体如下:
+=,-=,*=,/=,%=,<<=,>>=,&=,^=,|=。
例如:var1+=var2; 等价 var1=var1+var2;
5、条件运算符条件运算符是C++中唯一的三目运算符,它的使用较为灵活,在某些情况下可以用来代替if—else语句。条件运算符的语法形式如下:
expr1?expr2:expr3;
根据expr1计算的结果决定计算expr2(结果非0)或expr3(结果为0)。整个表达式的最终返回结果由表达式expr2或expr3决定。
例如:5>6?x=5:x=8;
6、自增、自减运算符自增运算符“++”和自减运算符“――”主要用在循环语句中,为循环控制变量提供格式紧缩的加1和减1运算。
例如,i++; 等价于 i=i+1;
自增和自减运算符对其操作数都进行赋值,且每种运算符都有前缀和后缀两种用法。当使用前缀用法(例如++i)时,程序首先对该操作数进行引用,再对其进行加1或减1用赋值;当使用后缀用法(例如i++)时,程序首先对操作数进行加1或减1及赋值,再对该操作数进行引用。
[例2.9] 自增、自减运算符及其不同用法举例
//EX2_9.cpp
//自增、自减操作符及其不同用法
#include<iostream.h>
void main()
{
int var1,var2;
var1=10;
cout<<"var1="<<var1<<'\n';
var2=var1++;
cout<<"var1++="<<var1<<'\n';
cout<<"var2=var1++="<<var2<<'\n';
cout<<"\n\n\n";
var1=10;
cout<<"var1="<<var1<<'\n';
var2=++var1;
cout<<"++var1="<<var1<<'\n';
cout<<"var2="<<var2<<'\n';
cout<<"\n\n\n";
var1=10;
cout<<"var1="<<var1<<'\n';
var2=var1--;
cout<<"var1--="<<var1<<'\n';
cout<<"var2=var1--="<<var2<<'\n';
cout<<"\n\n\n";
var1=10;
cout<<"var1="<<var1<<'\n';
var2=--var1;
cout<<"--var1="<<var1<<'\n';
cout<<"var2="<<var2<<'\n';
}
7、位运算符在C++语言中提供了大量的低级操作函数,使得它可以完成通常由汇编语言完成的大部分工作。支持按位运算便是对低级操作支持的重要组成部分。表2.7列出了6个位运算符。
表2.7 C++中的位运算符运算符
运算操作
使用例子
~
按位取反
~var
<<
左移
var1<<var2(移位的位数)
>>
右移
var1>>var2(移位的位数)
&
按位与
var1&var2
^
按位异或
var1^var2
|
按位或
var1|var2
位运算符将其操作数看作一个二进制位的集合,各二进制位的取值只能是0和1中的一个。通过位运算,程序员可以对某个数据中的特定二进制位进行检测或为给定的二进制位赋值。
注意:位运算符的操作数只能是基本数据类型中的char和int类型及其各种变体而不支持float、double、void或其他更复杂的数据类型。对于整型数据,由于符号位在不同位运算符中的处理方法不同,且受到机器类型的影响。因此,为了保证程序运行的正确性,建议使用unsigned int类型数据作为位运算符的操作数。
利用位运算符来设置及检测奇偶校验位,也可以用于简单的加密程序等。
8、sizeof运算符
sizeof运算符通知编译程序其操作数在内存中占用的字节数,它返回变量或括号中的类型修饰符的字节长度。这是在程序编译时确定的,与程序的运行状态无关。其格式如下:
sizeof(type_specifier); 或 sizeof(variable_name);
使用sizeof运算符的主要目的是为了增强程序的可移植性,使之不会由于机器表示同一数据类型时存在字节长度不同而导致程序出错,从而确保程序可以在不同的硬件环境上正常运行。
C++表达式在C++中,表达式是由运算符、常量、变量和表达式按照一定的语法规则组合而成的。表达式在程序执行时完成一个或多个操作,并最终返回一个结果。若无特别说明,表达式的返回结果是一个右值,其数据类型由参与运算的数据的数据类型来确定。
当不同数据类型的常量和变量在一个表达式中混合使用时,它们在计算时将被转换成同一数据类型。通常C++编译器在进行类型转换时遵循“向上转换”的原则,即将涉及数据的数据类型转换为其中字长最长的数据类型。转换规则如下所示:
(1)所有的char和short int都被转换为int;
(2)对所有的float被转换为double;
(3)对所有的操作数,若其中一个为long double,则另一个也被转换为long double;
(4)否则,如果一个操作数为double,则另一个也被转换为double;
(5)否则,如果一个操作数为long,则另一个也被转换为long;
(6)否则,如果一个操作数为unsigned,则另一个也被转换为unsigned;
在按上述规则进行数据类型转换后,同一表达式中的操作数都变成了相同的数据类型数据,而表达式的运算结果的数据类型也就是这些数据的数据类型。
当然,程序员也可以通过强制类型转换强迫表达式中的某些数据转换为某一特定的数据类型。强制数据类型的形式如下所示:
(type-specifier)variable (如:(double)var;)