【C/C++】运算符及其优先级

首先介绍表达式及语句的基本概念。

表达式:

一个表达式由运算量(亦称操作数)和运算符组成。例如,算术表达式A+B是由二元运算符"+"和操作数A、B组成的。A、B分别称为运算符+的左、右操作数。

在表达式中,一元运算符通常写在它的操作数前面,如-A,这种形式称为前缀形,但也有也在操作数的后面,如A++,这种形式称为后缀形。二元运算符一般写在两个操作数的中间,如X+Y。

表达式的性质在后文中会有所提及,如自增、自减运算符只能作用于变量,而不能作用于常量或表达式。

语句:

语句通常是以分号结尾的,从功能上说,语句大体可分为执行性语句和说明性语句两大类。说明性语句旨在定义各种不同数据类型的变量或运算。执行性语句旨在描述程序的动作。执行性语句又可分为赋值语句、控制语句和输入/输出语句。

语句和表达式的区别是:表达式是一个值,而语句没有值。

1. 赋值语句

在赋值语句中,赋值运算符“=”左、右两边的变量名扮演着两种不同的角色。对赋值运算符右边的B我们需要的是它的值;对左边的A我们需要的是它所代表的存储单元(的地址)。为了区分一个名字的这两种特征,我们把一个名字所代表的单元(地址)称为该名的左值;把一个名字的值称为该名的右值。

    赋值操作符的左操作数必须是非const的左值。

2. 自增与自减运算符

++和--,分别称为自增运算符和自减运算符,它们是一元算术运算符。学习和应用这两个运算符时应注意前缀运算和后缀运算的区别。

2.1 前缀运算与后缀运算

仍以自增运算符为例,该运算符可作用在变量之前,例如++i,称为前缀运算;也可作用于变量之后,例如i++,称为后缀运算。

以++操作为例,对于变量a,++a表示取a的地址,增加它的内容,然后把值放在寄存器中;a++表示取a的地址,把它的值装入寄存器,然后增加内存中a的值。

自减运算符与自增运算符类似,只要将加1改为减1即可。即前缀运算是“先变后用”,而后缀运算是“先用后变”。

2.2 自增、自减运算符作用的对象

自增、自减运算符只能作用于变量,而不能作用于常量或表达式。只要是标准类型的变量,不管是整型、实型,还是字符型、枚举型都可以作为这两个运算符的运算对象。

如以下四个表达式都是合法的:

1) i++ + j++;

2) ++i + (++j);

3) ++a + b++;

4) ++array[--j];

而++6、(i+j)++、‘A’++、++i+++j、(&p)++这五个表达式都是不合法的。

为什么i+++j++合法,而++i+++j却不合法呢?这是因为C/C++的编译器对程序编译时,从左到右尽可能多地将字符组合成一个运算符或标识符,因此i+++j++等效于(i++)+(j++),两个"++"作用的对象都是变量,这是合法的;而++i+++j等效于++(i++)+j,第一个"++"作用的是表达式"i++",这是不允许的。

【示例】下列代码是否有错误,若有错误请指出,若没有,请确定a的值是多少?

1 int main()
2 {
3     int a = 3;
4     a += (a++);
5     a += (++a);
6     (++a) += (a++);
7     (a++) += a;
8     return 0;
9 }

【参考答案】

 1 int main()
 2 {
 3     int a = 3;         // 此句执行后,a = 3
 4     a += (a++);     // 此句执行后,a = 7
 5     a += (++a);     // 此句执行后,a = 16
 6     (++a) += (a++); // 此句执行后,a = 35
 7     (a++) += a;      // 编译错误,a++是右值,只能位于等号的右边
 8                     // 左值既可以位于等号的左边,也可以位于等号的右边
 9     return 0;
10 }

2.3 ++、--运算符的结合方向

表达式k=-i++等效于k=(-i)++还是k=-(i++)?因为负号运算符和自增运算符优先级相同,哪一个正确就得看结合方向。自增、自减运算符及负号的结合方向是从右向左的。因此,上式等效于k=-(i++)。

注意:不用因为k=-i++等效于k=-(i++)就先做"++"运算!这里采用的是"先用后变",即先拿出i的值做负号"-"运算,把这个值赋给变量k之后变量i才自增。

3. 关系与逻辑运算符

关系操作符(<、<=、>、>=)具有左结合性。事实上,由于关系运算操作符返回bool类型的结果,因此很少使用其左结合特性。如果把多个关系操作符串接起来使用,结果往往出乎意料:

if (i < j < k)  { /*...*/ }

在这种写法中,只要k大于1,上述表达式的值就为true。这是因为第二个小于操作符的左操作数是第一个小于操作符的结果:true或false。也就是,该条件将k与整数0或1做比较。为了实现我们想要的条件检验,应重写上述表达式如下:

if (i < j && j < k) { /*...*/ }

逻辑操作符将其操作数视为条件表达式:首先对操作数求值;若结果为0,则条件为假(false),否则为真(true)。仅当逻辑与(&&)操作符的两个操作数都为true,其结果才为true。对于逻辑或(||)操作,只要它的两个操作数之一为true,它的值为true。

给定以下两种形式:

expr1 && expr2  // logical AND
expr1 || expr2  // logical OR

仅当由expr1不能确定表达式的值时,才会解expr2。

逻辑与和逻辑或操作符总是先计算其左操作数,然后再计算右操作数。只有在仅靠左操作数的值无法确定该逻辑表达式的结果时,才会求解右操作数。我们常常称这种求值策略为"短路求值"。

4. 位运算符

位操作符使用整型的操作数。位操作符将其整型操作数视为二进制位的集合,为每一位提供检验和设置功能。C语言提供了以下六种位运算符。

操作符 功能 单双目 用法
& 按位与 双目运算符 expr1 & expr2
按位或 双目运算符 expr1 | expr2 
^ 按位异或 双目运算符 expr1 ^ expr2
~ 取反 单目运算符 ~expr
<< 左移 双目运算符 expr1 << expr2
>> 右移 双目运算符 expr1 >> expr2

【示例】不用算术运算符实现两个数的加法。

【解析】对于二进制加法运算,若不考虑进位,则1+1=0,1+0=1,0+1=1,0+0=0,通过对比异或,不难发现,此方法与异或类似。因而排除进位,加法可以用异或来实现。

然后考虑进位,0+0的进位为0,1+0的进位为0,0+1的进位为0,只有1+1时进位才为1,该操作与位运算的&操作相似。

那么加法运算可以这样实现:

1) 先不考虑进位,按位计算各位累加(用异或实现),得值a;

2) 然后计算进位,并将进位的值左移,得值b,若b为0,则a就是加法运算的结果,若b不为0,则a+b即得结果(递归调用该函数)。

参考代码如下:

1 int addWithoutArithm(int a, int b)
2 {
3     if (b == 0) return a; // 当没有进位时
4     int sum = a^b;
5     int carry = (a & b) << 1;
6     return addWithoutArithm(sum, carry);
7 } 

【示例】如果X大于0并小于65536,用移位法计算X乘以255的值为( )。(2011网易游戏)

【解答】:-X + (X << 8)。

5. 运算符优先级表

表达式的运算顺序主要由以下两种因素决定:

1) 运算符的优先级:程序总是先执行优先级较高的运算符;

2) 运算符的结合性:当运算符的优先级相同时,运算符的结合性决定运算顺序。对从左到右的运算符,先执行左边的部分,对从右向左的运算符,则先执行右侧的部分。

C语言的运算符优先级表如下所示:

优先级 运算符 名称或含义 使用形式 结合方向 说明
1 [] 数组下标 数组名[常量表达式] 左到右  
1 () 圆括号 (表达式)/函数名(形参表) 左到右  
1 . 成员选择(对象) 对象.成员名 左到右  
1 -> 成员选择(指针) 对象指针->成员员 左到右  
2 - 负号运算符 -表达式 右到左 单目运算符
2 (类型) 强制类型转换 (数据类型)表达式 右到左  
2 ++ 自增运算符 ++变量名/变量名++ 右到左 单目运算符
2 -- 自减运算符 --变量名/变量名-- 右到左 单目运算符
2 * 取值运算符 *指针变量 右到左 单目运算符
2 & 取地址运算符 &变量名 右到左 单目运算符
2 ! 逻辑非运算符 !表达式 右到左 单目运算符
2 ~ 按位取反运算符 ~表达式 右到左 单目运算符
2 sizeof 长度运算符 sizeof(表达式) 右到左  
3 / 表达式/表达式 左到右 双目运算符
3 * 表达式*表达式 左到右 双目运算符
3 % 余数(取模) 整型表达式%整型表达式 左到右 双目运算符
4 + 表达式+表达式 左到右 双目运算符
4 - 表达式-表达式 左到右 双目运算符
5 << 左移 变量<<表达式 左到右 双目运算符
5 >> 右移 变量>>表达式 左到右 双目运算符
6 > 大于 表达式>表达式 左到右 双目运算符
6 >= 大于等于 表达式>=表达式 左到右 双目运算符
6 < 小于 表达式<表达式 左到右 双目运算符
6 <= 小于等于 表达式<=表达式 左到右 双目运算符
7 == 等于 表达式==表达式 左到右 双目运算符
7 != 不等 表达式!=表达式 左到右 双目运算符
8 & 按位与 表达式&表达式 左到右 双目运算符
9 ^ 按位异或 表达式^表达式 左到右 双目运算符
10 按位或 表达式|表达式 左到右 双目运算符
11 && 逻辑与 表达式&&表达式 左到右 双目运算符
12 || 逻辑或 表达式||表达式 左到或 双目运算符
13 ?: 条件运算符 表达式1?表达式2:表达式3 右到左 三目运算符
14 = 赋值运算符 变量=表达式 右到左  
14 /= 除后赋值 变量/=表达式 右到左  
14 *= 乘后赋值 变量*=表达式 右到左  
14 %= 取模后赋值 变量%=表达式 右到左  
14 += 加后赋值 变量+=表达式 右到左  
14 -= 减后赋值 变量-=表达式 右到左  
14 <<= 左移后赋值 变量<<=表达式 右到左  
14 >>= 右移后赋值 变量>>=表达式 右到左  
14 &= 按位与后赋值 变量&=表达式 右到左  
14 ^= 按位异或后赋值 变量^=表达式 右到左  
14 |= 按位或后赋值 变量|=表达式 右到左  
15 , 逗号运算符 表达式,表达式,... 左到右 从左向右顺序计算

运算符优先级有几个简单的规则:

1) 括号,下标,->和.(成员)最高;

2) 单目的比双目的高;算术双目比其他双目的高;

3) 移动运算高于关系运算;关系运算高于按位运算(与,或,异或);按位运算高于逻辑运算;

4) 三目的只有一个条件运算,低于逻辑运算;

5) 赋值运算仅比","高,且所有的赋值运算符优先级相同,结合访问从右向左。

时间: 2024-10-14 10:33:45

【C/C++】运算符及其优先级的相关文章

(4)javascript的运算符以及运算符的优先级

                                运算符的使用方法 在javascript的程序中要完成各种各样的运算,是离不开运算符的. 在javascript中,按运算符类型可以分为算术运算符.赋值运算符.比较运算符.逻辑运算符.条件运算符等. ( 图片来自于W3School离线手册) 算术运算符案例: <!doctype html> <head> <meta http-equiv="content-type" content="

javascript中运算符的优先级

运算符优先级 JavaScript中的运算符优先级是一套规则.该规则在计算表达式时控制运算符执行的顺序.具有较高优先级的运算符先于较低优先级的运算符执行.例如,乘法的执行先于加法. 下表按从最高到最低的优先级列出JavaScript运算符.具有相同优先级的运算符按从左至右的顺序求值. 其中圆括号可用来改变运算符优先级所决定的求值顺序.这意味着圆括号中的表达式应在其用于表达式的其余部分之前全部被求值. z = 78 * (96 + 3 + 45) 在该表达式中有五个运算符: =, *, (), +

[c语言]运算符的优先级与结合性

c语言中运算符的优先级和结合性常常被人混淆一谈,本文目的在于简单谈谈两者的区别.本文举几个简单的例子说明,这些运算符也特别常用. 首先要明白的是:优先级决定表达式中各种不同的运算符起作用的优先次序:而结合性则在相邻的运算符的具有同等优先级时,决定表达式的结合方向. [赋值运算符“=”] 对于赋值运算符来说,常会用到的是连续赋值的表达式.比如“a=b=c”. 这里的变量b的两边都是赋值运算,优先级当然是相同的,那么应该怎么理解这个表达式呢?我们知道,赋值表达式具有“向右结合”的特性,这就表示这个表

java基础----&gt;运算符及其优先级

一.运算符 1)'/'  除法运算符 a) 如果是两个整数相除,只取整数商,如7/2=3 b) 如果是和浮点数相除,则取浮点数为商,如7/2F=3.5 2)自增,自减运算符"++""--" a) 使用自增或自减运算符的操作数必须是整数或者浮点数,char以及 boolean型的数不可以使用"++""--" 3)比较运算符,注意这些运算符的操作数的可取类型 4)逻辑运算符&&.&.|| .! a) 这些逻

python运算符的优先级顺序

最近开始学习python,听大家说python很强大,可以作为脚本语言,支持面向对象.面向过程编程,兼具编译性和解释性的一门动态语言.作为一名程序员有必要掌握这一门强大的"胶水语言".最近回顾了下,纪录一下运算符的优先级顺序,以下运算符的优先级依次递增: 运算符 Lambda #运算优先级最低 逻辑运算符: or 逻辑运算符: and 逻辑运算符:not 成员测试: in, not in 同一性测试: is, is not 比较: <,<=,>,>=,!=,==

【黑马程序员】————运算符的优先级

运算符的优先级(从高到低) 优先级 描述 运算符 1 括号 ().[] 2 正负号 +.- 3 自增自减,非 ++.--.! 4 乘除,取余 *./.% 5 加减 +.- 6 移位运算 <<.>>.>>> 7 大小关系 >.>=.<.<= 8 相等关系 ==.!= 9 按位与 & 10 按位异或 ^ 11 按位或 | 12 逻辑与 && 13 逻辑或 || 14 条件运算 ?: 15 赋值运算 =.+=.-=.*=.

运算符和表达式,以及运算符的优先级

1.什么是运算符: 用于执行程序代码运算,会针对一个或以上操作数项目来进行运算. 2.运算符的分类: 用途分:基本运算符,条件运算符,逻辑运算符. 按操作的数分:一目,双目,三目运算. 3.什么是表达式: 是由数字.算符.数字分组符号(括号).自由变量和约束变量等以能求得数值的有意义排列方法所得的组合. 4.运算符的优先级: (1) 一目>双目>三目 (2) 有括号的最先 补充:自增1,自减1运算符均为单目运算,都具有右结合性.可有以下几种形式: ++i:i自增1后再参与其它运算. --i:i

[转]Java 运算符的优先级

Java 运算符的优先级(从高到低) 优先级 描述 运算符 1 括号 ().[] 2 正负号 +.- 3 自增自减,非 ++.--.! 4 乘除,取余 *./.% 5 加减 +.- 6 移位运算 <<.>>.>>> 7 大小关系 >.>=.<.<= 8 相等关系 ==.!= 9 按位与 & 10 按位异或 ^ 11 按位或 | 12 逻辑与 && 13 逻辑或 || 14 条件运算 ?: 15 赋值运算 =.+=.-

慕课网-安卓工程师初养成-3-9 Java中运算符的优先级

来源 http://www.imooc.com/code/1315 所谓优先级,就是在表达式中的运算顺序.Java 中常用的运算符的优先级如下表所示: 级别为 1 的优先级最高,级别 11 的优先级最低.譬如,x = 7 + 3 * 2  得到的结果是 13 “先乘后加”嘛! PS:大家没必要去死记运算符的优先级顺序,实际开发中,一般会使用小括号辅助进行优先级管理.例如: 分析:小括号优先级最高,因此 1. 执行 a + 18 ,结果为 30 2. 执行( a + 18 ) % 4 取模,结果为