C语言运算符优先级
优先级 | 运算符 | 名称或含义 | 使用形式 | 结合方向 | 说明 |
1 | [] | 数组下标 | 数组名[常量表达式] | 左到右 | -- |
() | 圆括号 | (表达式)/函数名(形参表) | -- | ||
. | 成员选择(对象) | 对象.成员名 | -- | ||
-> | 成员选择(指针) | 对象指针->成员名 | -- | ||
| |||||
2 | - | 负号运算符 | -表达式 | 右到左 | 单目运算符 |
~ | 按位取反运算符 | ~表达式 | |||
++ | 自增运算符 | ++变量名/变量名++ | |||
-- | 自减运算符 | --变量名/变量名-- | |||
* | 取值运算符 | *指针变量 | |||
& | 取地址运算符 | &变量名 | |||
! | 逻辑非运算符 | !表达式 | |||
(类型) | 强制类型转换 | (数据类型)表达式 | -- | ||
sizeof | 长度运算符 | sizeof(表达式) | -- | ||
| |||||
3 | / | 除 | 表达式/表达式 | 左到右 | 双目运算符 |
* | 乘 | 表达式*表达式 | |||
% | 余数(取模) | 整型表达式%整型表达式 | |||
4 | + | 加 | 表达式+表达式 | 左到右 | 双目运算符 |
- | 减 | 表达式-表达式 | |||
5 | << | 左移 | 变量<<表达式 | 左到右 | 双目运算符 |
>> | 右移 | 变量>>表达式 | |||
| |||||
6 | > | 大于 | 表达式>表达式 | 左到右 | 双目运算符 |
>= | 大于等于 | 表达式>=表达式 | |||
< | 小于 | 表达式<表达式 | |||
<= | 小于等于 | 表达式<=表达式 | |||
7 | == | 等于 | 表达式==表达式 | 左到右 | 双目运算符 |
!= | 不等于 | 表达式!= 表达式 | |||
| |||||
8 | & | 按位与 | 表达式&表达式 | 左到右 | 双目运算符 |
9 | ^ | 按位异或 | 表达式^表达式 | 左到右 | 双目运算符 |
10 | | | 按位或 | 表达式|表达式 | 左到右 | 双目运算符 |
11 | && | 逻辑与 | 表达式&&表达式 | 左到右 | 双目运算符 |
12 | || | 逻辑或 | 表达式||表达式 | 左到右 | 双目运算符 |
| |||||
13 | ?: | 条件运算符 | 表达式1? 表达式2: 表达式3 | 右到左 | 三目运算符 |
| |||||
14 | = | 赋值运算符 | 变量=表达式 | 右到左 | -- |
/= | 除后赋值 | 变量/=表达式 | -- | ||
*= | 乘后赋值 | 变量*=表达式 | -- | ||
%= | 取模后赋值 | 变量%=表达式 | -- | ||
+= | 加后赋值 | 变量+=表达式 | -- | ||
-= | 减后赋值 | 变量-=表达式 | -- | ||
<<= | 左移后赋值 | 变量<<=表达式 | -- | ||
>>= | 右移后赋值 | 变量>>=表达式 | -- | ||
&= | 按位与后赋值 | 变量&=表达式 | -- | ||
^= | 按位异或后赋值 | 变量^=表达式 | -- | ||
|= | 按位或后赋值 | 变量|=表达式 | -- | ||
| |||||
15 | , | 逗号运算符 | 表达式,表达式,… | 左到右 | -- |
两个重要的原则:
1. 同一优先级的运算符,运算次序由结合方向所决定。比较简单的是只有单目运算符和扶植运算符的是从右到左其余都是从左到右
2. 简单记就是:! > 算术> 关系 > && > || > 赋值
3.逗号最低(这个可以忽略)
从网上找了个记忆口诀:http://wenku.baidu.com/view/9d0baf3d87c24028915fc393.html
最好找点题目做做,接下来我会更新一点题目:
int k=15,t;
t=k&&k==5&&++k;
问K=?,T=?
要理解这个问题分三步:
1.重点记住
=的优先级比&&,==,++都要低,且它的结合性为 右 结合性
&&的优先级低于==,++,且它的结合性为 左 结合性
==的优先级低于++,且它的结合性为 左 结合性
++的优先级这这个表达式中最高,且它的结合性为 右 结合性
2.时刻想到
逻辑运算符&&和||会出现短路现象:
* && * :当&&的左边为假时短路,此时不再执行&&右边的表达式(注意是&&右边的另一个表达式,而不是右边所有到到语句结束的表达式!!)
* || * :当||的左边为真时短路,些时不再执行||右边的表达式
3.详细推导
在表达式t=k&&k==5&&++k中,根据运算符的优先级和结合性来确定,表达式相当于:
t= ( k && (k==5) && (++k) )
根据&&的结合性,表达中肯定先验证第一个&&的两边为:k && (k==5)
由于k为15,左边为真,并没有短路,所以继续看&&的右边,表达k==5明显为假,值为0,所以表达式k && (k==5)为假,值为0,此时表达简化为:
t= ( 0 && (++k) )
此时表达式中的&&为原表达式中的第二个&&,再看这个表达式的0 && (++k),很明显&&的左边为0,发生短路,那么不再执行&&的(++k),所以k保持原值不会为16,此时原表达式又进一步简化为:
t=0
最后,t的值为0,k的值不变为15
这样解释,你明白吗?
注意:计算对表达式的是利用栈作工具,并且是从左到右的扫描,并且每次都是尽最大可能的结合,
比如:a=32222+1115*888,在扫描识别表达式的时候,不可能到a=3就停止了,而是尽最大可能的结合,一直要扫描到a=32222+才暂时停止,为什么?因为32222这个数字尽最大可能结合完成了,但还要多往后面扫描一个字符,只有这样才能知道不能再和+结合了,但此时并不执行a=32222,为什么?因为运行符是有优先级的,刚才扫描到+号的时候就发现结合完成了,但同时进行判断+的优先级比=高,所以先把变量a和操作符=入栈,挂起=运算,优先处理+号
又因为+号的双目运算符,要两个运算数据,现在有了一个32222,还差一个,所以又往后扫描,还是尽最大努力结合,到1115*的时候又结束,+号的两个运算数据全部在了,便扫描暂停的同时又发现最后一个运算符为*优先级比+还高,又要把+号操作和1115入栈,又由于*也是一个双目运算符,所以还差一个运算数据,还要扫描,这次直接到;号,发现整个表达式结束了,且*的两个运算数据都在了,且1115*888后面没有跟比*优先级更高的运算符,所以要计算1115*888,1115出栈,计算相乘,得到结果,再从栈中弹出32222和+操作进行加法运算,最后再处理赋值运算,所以计算机不是人,它不会像人一样直接就找到优先级最高的*号进行运算
再回到刚才的问题上,表达式t=k&&k==5&&++k从左到右的扫描,你现在还能认为它像人一样,最先执行++k吗?
只有扫描到了,且满足运算符的优先级、结合数目等要求了才轮得到它去执行!!!这样看来它又怎么会先执行++?
这种问题可以从数据结构、编译原理、C/C++的有关书籍中可以查到