C++语言的运算符涵盖的范围很宽,它把除了控制语句和输入/输出语句以外的几乎所有的基本操作都作为运算符处理,例如将赋值符“=”作为赋值运算符。C++的运算符见表2.7。
基本算术运算符包括下面几种:
1)+(加法运算符,或正值运算符,如3+5、+3)。
2)-(减法运算符,或负值运算符,如5-1、-4)。
3)*(乘法运算符,如3*5)。
4)/(除法运算符,如5/3)。
5)%(模运算符,或称求余运算符,%两侧均应为整型数据,如7%3的值为4)。
说明 两个整数相除的结果为整数,如5/3的结果为1,舍去小数部分。但是如果除数或被除数中有一个为负值,则舍入的方向是不固定的。例如:-5/3在有的系统中得到的结果为-1,在有的系统中得到的结果为-2。多数编译系统采取“向零取整”的方法。
如果参加+、-、*、/运算的两个数中有一个数为实数或双精度数,则结果是double型的数,因为所有实数都按double型进行运算。
关系运算符主要用作比较两个量的大小、两个量是否相等或者两个量是否不相等。所以关系操作符主要做比较运算。运算的结果只有两种,1或者0。如果结果为1表示条件成立,如果结果为0表示条件不成立。在通常情况下,结果为1称为“true(真)”,反之结果为0时称为“false(假)”。
以下是C++的关系运算符,如表2.8所示。
例如以下的代码:
int x=10;
int y=12;
if(x!=y)
{
//……
}
其中代码x!=y表示判断x是不是不等于y,如果x不等于y那么判断成立,如果x等于y那么判断不成立。
关系运算符不仅可以用于整型变量的比较,而且可以用于任何基本数据类型的比较。
关系运算符中的>、>=、<和<=的优先级相同,==和!=的优先级相同,而且>、>=、<和<=的优先级高于==和!=。
逻辑运算符用于对包含关系运算符的表达式进行合并或取反。逻辑运算符有3种,如表2.9所示。
□对于逻辑运算符的表达式,如果结果为“真”则值为1,如果结果为“假”则值为0。如下代码:
int a=10;
int b=5;
printf("%d",a>b);
打印显示的结果是1。
□逻辑运算符&&和||中间不能有空格。
□假设变量a既大于0,又小于6(a>0,a<6),这时可以使用逻辑与来表达,写作a>0&&a<6。如果假设变量a可以小于0,也可以大于10(a<0,a>10),这时可以使用逻辑或来表达,写作a<0||a>10。
□逻辑非运算符用于对表达式的值取反。这里需要注意的是,如果是非0那么表示为真,如果是0那么表示为假。所以(!6)的值等于0。
□逻辑运算符的优先级低于算术运算符的优先级。如:200>96+8则等价于200>(96+8),即为真。
位运算符主要用作数据类型的位运算,C++语言提供6种位运算符,如表2.10所示。
例如操作数10,其二进制表示为1010,位运算提供二进制位的操作。
□10&12相当于二进制的1010&1100,其运算结果是二进制的1000,换成十进制则运算结果为8。这是因为位与运算符当相同位都是1时为1,相同位有一个为0时则为0。
□10|12相当于二进制的1010|1100,其运算结果是二进制的1110,换成十进制则运算结果为14。这是因为位或运算符中当相同位有一个是1时为1,相同位二者为0时为0。
□10^12相当于二进制的1010^1100,其运算结果是二进制的0110,换成十进制则运算结果为6。这是因为位异或运算符中当相同位相同时为0,当相同位二者不同时为1。
□~12相当于二进制的~1100,其运算结果是二进制的0011,换成十进制则运算结果为3。这是因为位取反运算符,当位上为1时变成0,当位上为0时变成1。
□10<<1相当于二进制的1010<<1,其运算结果为10100,换成十进制则运算结果为20。这是因为(10<<1)位左移运算符使操作数的所有位向左移动了1位,每移动一位相当于操作数乘以2,如果移动2位那么乘以4,移动3位乘以8,依此类推(注意溢出情况)。
□10>>1相当于二进制1010>>1,其运算结果为101,换成十进制则运算结果为5。这是因为(10>>1)位右移运算符使操作数所有的位向右移动了1位,每移动一位相当于操作数除以2。
上面讲解了位运算符,那么位运算符有什么用处,下面简单介绍。
位与运算符(&)的特点是,运算符两边的操作数,相同位都是1时为1,相同位有一个为0时则为0。这样可以用位与运算符取出某几个位上的结果。比如某个数值x,若想知道x的后3位是什么,可以这样写程序:
int main()
{
int x=18;
int a=(x&3);
printf("%d",a);
return 0;
}
运行上面的代码,其运算结果为2,即18的后3位是二进制010。为什么x要和3取位与呢,那是因为3的二进制是111,如果18的低3位是0那么该位结果为0,如果该位是1那么该位的结果也为1。
位异或运算符(^)可以用于简单的加密运算,现在用实例2.7简单说明。
【实例2.7】 位异或运算符的使用。
int main()
{
int x=216;
int a=x^116;
printf("%d\r\n",a);
int c=a^116;
printf("%d\r\n",c);
return 0;
}
【输出结果】实例2.7的输出结果如下所示。
172
216
【代码剖析】
最后输出的数值c,即等于x。
sizeof运算符以字节形式给出其参数的存储大小。参数可以是一个表达式或括在括号内的类型名。参数的存储大小由参数的类型决定。
使用sizeof运算符最常见的一种方法是将变量名、或数据类型括在括号内,比如:sizeof(a)、sizeof('y')、sizeof(5)、sizeof(unsigned int)。
sizeof运算符的结果类型是size_t,头文件中,它被使用typedef定义为unsigned int类型。该类型保证能容纳实现所建立的最大对象的字节大小。
□sizeof(char)、sizeof(unsigned char)的大小为1,即占用1个字节。
□sizeof(bool)的大小为1,即占用1个字节。
□sizeof(short)、sizeof(unsigned short)的大小为2,即占用2个字节。
□sizeof(int)、sizeof(unsigned int)的大小为4,即占用4个字节。
□sizeof(long)、sizeof(unsigned long)的大小为4,即占用4个字节。
□sizeof(float)的大小为4,即占用4个字节。
□sizeof(double)的大小为8,即占用8个字节。
C++可以利用强制类型转换运算符将一个表达式转换成所需的类型,例如:
(double)a //将a转换成double类型
(int)x+y //将x+y的值转换成整型
(float)(5%3) //将5%3的值转换成float类型
C++语言中的强制类型转换是通过类型转换运算实现的。
其一般形式为:
(类型说明符)(表达式)
其功能是把表达式的运算结果强制转换成类型说明符表示的数据类型。例如:
(float)a 将a转换成浮点类型
(int)(a*b)将a 乘以b的结果转换为整型
需要注意的地方是:
□将需要强制类型转换的表达式都用括号括起来,例如(int)(a*b)不能写成(int)a*b,因为(int)a*b其含义是将a强制转换成整型然后与b相乘,其运算结果不一定为整型。
□还一个重要的地方是,在没有强制类型转换时,当表达式中含有浮点数的时候,其结果为浮点数;如果表达式中含有无符号操作数的,其运算结果为无符号型数据。例如:
int main()
{
unsigned int a=100;
int b=-200;
double c=(double)(a+b);
printf("%.0lf\n",c);
return 0;
}
这段代码,感觉上会输出-100或者跟-100相接近的数据,但是程序意外输出了4294967196。如果将unsigned int a=100;改写成int a=100;则程序将输出-100。所以在写程序代码时,要注意是否都是无符号型数据。
再看下面的例子:
int main(int argc, char*argv[])
{
int a=5;
int b=2;
double c=(double)(a/b);
printf("%lf\n",c);
return 0;
}
上面的程序输出结果感觉上会是2.5,但是程序输出是2.000000。
怎样改写代码才能得到2.5这样的结果呢?请看下面的代码:
int main(int argc, char*argv[])
{
int a=5;
int b=2;
double c=(double)a/b;
printf("%lf\n",c);
return 0;
}
这段代码才能输出2.5。原因在于当表达式中含有浮点数时,其结果为浮点数;如果表达式中含有无符号操作数,其运算结果为无符号型数据。在上面的代码中,已经将a强制转换成了double数据类型((double)a/b),所以整个表达式都采用浮点运算,而((double)(a/b))这种写法是将a/b的运算结果已经计算出来后再转化成浮点数。
□无论是强制转型还是自动转型,都是为了本次计算的需要,对变量的类型做了一个临时转变,而不改变数据原来的类型定义。
请看下面的代码:
int main(int argc, char*argv[])
{
int a=10;
double c=(double)a;
printf("%lf\n",c);
return 0;
}
在此代码中,a为了赋值给c,被临时强制转换成了双精度浮点类型,但是当运算过后,a还是整型数。
□精度高的数据转化为精度低的数据,会造成数据丢失,而且编译器可能会发出警告,请看下面的代码:
int main(int argc, char*argv[])
{
int a=80000;
short b=a;
printf("%d",b);
return 0;
}
程序输出的结果是14464。而不是80000,这是因为在32位操作系统下,int型数据占用4个字节,而short是占2个字节,short能表示的最大数是2的15次方减1也就是32767。所以在编程时应该注意。
C++语言规定了各种运算符的优先级与结合性。在表达式求值时,先按运算符的优先级高低顺序执行,例如先乘除后加减。如表达式a-b*c, b的左侧为减号,右侧为乘号,而乘号优先于减号,因此,相当于a-(b*c)。如果在一个运算对象两侧运算符的优先级相同,如a-b+c,则按规定的“结合方向”处理。
C++语言规定了各种运算符的结合方向,算术运算符的结合方向为“自左至右”,即先左后右。因此b先与减号结合,执行a-b的运算,再执行加c的运算。“自左至右的结合方向”又称“左结合性”,即运算对象先与左面的运算符结合。
算术表达式由常量、变量、函数、圆括号、运算符等组成。一个常量、一个变量(已赋过值)、一个函数都是合法的表达式,是表达式的简单情况。
一般情况下,算术表达式可包含更多的运算数据、运算符、圆括号,例如:
(200/20+6)*8+10%6-36
表达式的运算过程和数学中的规则一样,若有括号先运算括号内的子表达式。若有多层括号时,先运算最里层。同一层括号时,负号优先运算,接下来运算乘除,再运算加减;同一优先级从左到右进行运算。
用逻辑运算符将关系表达式或逻辑量连接起来的有意义的式子称为逻辑表达式。逻辑表达式的值是一个逻辑值,即“真”或“假”。C语言编译系统在给出逻辑运算结果时,以数字1表示“真”,以数字0表示“假”,但在判断一个量是否为“真”时,以非0表示“真”,以0表示“假”。
可以将逻辑表达式的运算结果(0或1)赋给整型变量或字符型变量。
注意 由于浮点数在计算机中不能非常准确地表示,所以,判断两个浮点数是否相同时,通常不使用关系运算符“等于”(==),而是利用区间判断方法来实现。为了判断x是否等于5.003,可利用如下逻辑表达式:
x>5.002&&x<5.004
当此逻辑表达式为“真”时,就可以认为x等于5.003。
赋值表达式是类似这样的句子:a=5;。赋值表达式的结果是将等号右边的值赋给左边的对象。运算的结合性为自右向左。
x=10; //表达式值为10
x=y=z=10; //表达式的值为10,运算过后,x, y,z的值都为10,先是将z赋值为10,接着y被赋值为10,最后x被赋值为10
x=(y=10)+(z=8); //表达式的值为18,其中y被赋值为10,z被赋值为8
除了“=”赋值表达式外,C++还提供了以下复合赋值表达式:+=,-=,*=,/=,%=,<<=,>>=,&=,^=和|=。以上几种复合表达式都是二元运算符,其运算优先级与“=”相同,结合性也是自右向左结合。例如:
x+=10; //等价于x=x+10;
x+=x-=(x*x); //等价于x=x+(x=x-x*x);
在C++中,逗号在某些情况下也是运算符,其表达式的使用方法如下所示:
<表达式1>,<表达式2>;
例如下面的代码:
x=5*6,x*3;
其运算结果为90。
表达式先计算表达式1,也就是x=5*6,然后再计算x=30*3。