众嘲炮:如何记C语言的运算符优先度

2019-12-27 18:54发布

本帖最后由 TBG3 于 2017-4-6 11:46 编辑

好像本论坛大多数程序员不记优先度,用括号来表达。当然是一种解决办法。但是你读别人的程序时呢? 人家不加括号你怎么办?

记的方法,扎实的办法就是死记,效果最好,这里就不做详细介绍了。

就介绍一种简单的方法,就五条。

一是单目运算符,包括数组,结构,++ -- ~ !之类,最优先。 因为神是唯一的神,所以好好敬服他吧。

第二是运算次优先,+ - * / <<  >>,因为资本主义世界,你要算清楚,不然肯定亏。注意这里面移位最不优先,因为人都不乐意地位变化。

第三是关系优先于逻辑,所以 > < == != 优先于与或非,与或非里面,个数多的,优先单个的,也就是说 & | 优先于 && ||

第四就是 赋值最不优先,因为等你都做出来之后,才会赋予你报酬。注意,因为 ? :里面有关系,所以在赋值里面最优先。

第五条是 单目里面的优先度,和2,3,4里面的优先度是一样一样的,赋值里面的优先度也跟2,3是一样一样的。
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
99条回答
zsfddd
1楼-- · 2020-01-08 08:55
我就记个大概,算术移位关系逻辑。
gycsy963
2楼-- · 2020-01-08 11:30
好记性不如圆括号
Ilove51andAVR
3楼-- · 2020-01-08 17:08
我对10楼进行了整理,方便记忆:

第1优先级:        括号运算符和成员运算符。例如:1:括号运算符:()   2:数组运算符:[]   3:成员运算符:->

第2优先级:        所有的单目运算符。例如:++(自增)、 --(自减)、 +(正号)、 -(负号)、~(按位取反)、 !(否定)   指针运算符:*(取值)、 &(取地址)

第3优先级:        乘号、除号、取余。例如:*(乘号)、 /(除号)、 %(取余)

第4优先级:        加号、减号。例如:+(加号)、 -(减号)

第5优先级:        移位运算符。例如:<<(左移)、 >>(右移)

第6优先级:        关系运算符。例如:>(大于)、 <(小于)、 >=(大于等于)、 <=(小于等于)

第7优先级:        等于号与不等于号。例如:==(等于号)、 !=(不等于号)

第8优先级:        位运算符。例如:&(按位与)、 ^(按位异或)、 |(按位或)

第9优先级:        逻辑运算符。例如: &&(逻辑与)、 ||(逻辑或)

第10优先级:        条件运算符(三目运算符)。例如:?:

第11优先级:        赋值运算符。例如:=、 +=、 -=、 *=、 /=、 &=、 ^=、 |=、 <<=、 >>=

第12优先级:        逗号运算符最低。例如:,(逗号)
laoshuhunya
4楼-- · 2020-01-08 20:16
本帖最后由 laoshuhunya 于 2017-4-8 23:56 编辑

这帖子就这么结了吗?那也太无趣了,老衲来说几句吧。

看到标题“...运算符优先度”,俺仿佛看到了漫天的板砖。楼主,如果你的标题没加“众嘲炮”三个字,估计早就被大神们的板砖掩埋几百楼了

事实上,C 语言运算符优先级很容易记的,总结一下就两句话,不过20分钟时间而已。为什么九九乘法表记得那么牢?因为有老师逼着啊!现在没人逼了,可以不记运算符优先级了,但请记住:括号不是万能的。

做技术不应该如此浮躁,产品的安全性、可靠性全在阁下一念之间啊。
如果各位还在使用C 语言开发产品,那么此刻请放下手中的板砖,静下心来。
在这之前,如果您还不了解“序列点”的概念,请先回头好好研究茴香豆有几种写法。

在讨论 *p++ 之前,请记住以下几个C 语言要点。

● 括号仅表示操作数之间的结合关系,并不要求编译器先对括号内的表达式求值。

例1:a + b + (c + d)
编译器可以先计算a + b,然后再计算c + d。如果a、b、c、d类型相同,编译器可以先计算a + c

例2:x() + (y() + z())
编译器可以先调用函数 x(),然后再调用函数 y() 和 z()

● 前缀自增/自减操作符的作用是:修改变量值,向使用它的表达式返回修改之后的值。
● 后缀自增/自减操作符的作用是:修改变量值,向使用它的表达式返回修改之前的值。
注意:修改的是变量的一个副本,该副本在下一序列点之前完成写回操作以更新变量值。C 语言没有规定这个写回操作是在返回值之前还是之后。


例3:c = a++;
这个表达式语句实现的操作是:自增 a,返回 a 自增之前的值并把此值赋给 c 。不能确定变量 a 的更新是发生在赋值之前还是之后(因为自增的是 a 的一个副本),但可以确定变量 a 的更新在序列点“;”之前完成。

● 除了赋值外,任何操作符都不会修改变量值。
注意:自增/自减操作符隐含赋值操作。
说明:函数操作符例外。


例4:a << 2
这是对 a 的一个副本进行移位操作,变量 a 本身并没有任何改变。只有 a = a << 2 才会修改 a 的值。

● 如果在两个连续序列点之间包含对某对象的写操作,并且写操作次数大于1次或者包含与写无关的读操作,则结果是未定义的。

例5:i = i++
在这个表达式中,i++隐含对 i 的写操作,而赋值运算符“=”又对 i 进行写操作,在连续的序列点之间对同一个变量 i 进行两次写操作,所以本例中的表达式不是合法的表达式,其结果是未定义的:也就是说,编译器可以产生任何结果,包括格式化你的设备。

例6:a = i++ + i++  或 a = (i++) + (i++)
在上面两个表达式中,i++隐含对 i 的写操作,在连续的序列点之间对同一个变量 i 进行两次写操作,所以本例中的表达式不是合法的表达式,其结果是未定义的:也就是说,编译器可以产生任何结果,包括格式化你的设备。

例7:a = i + i++
在这个表达式中,i++隐含对 i 的写操作,而赋值运算符“=”右侧第一个 i 进行与写入 i 无关的读操作,所以本例中的表达式不是合法的表达式,其结果是未定义的:也就是说,编译器可以产生任何结果,包括格式化你的设备。

例8:a[ i ] = i++
在这个表达式中,i++隐含对 i 的写操作,而a[ i ]又对 i 进行与写入 i 无关的读操作,所以本例中的表达式不是合法的表达式,其结果是未定义的:也就是说,编译器可以产生任何结果,包括格式化你的设备。

例9:i = i + 1
在这个表达式中,对变量 i 只进行1次写操作及与写入 i 有关的读操作,所以该表达式是合法的。

例10:i = i + i
在这个表达式中,对变量 i 只进行1次写操作及与写入 i 有关的读操作,所以该表达式是合法的。

有了以上基础,*p++就很好理解了。
这里“++”是后缀自增操作符,具有最高优先级,而“*”是前缀操作符,优先级低于后缀操作符,所以 *p++ 等同于 *(p++)
p++ 执行的操作是:自增p,向使用它的表达式返回p自增之前的值(即*p,而不是*(p+1))。因此,*(p++) 等同于如下操作:*p,p = p + 1
这里再次提醒下,对p的自增更新写回操作可能在*p之前,也可能在*p之后。
现在阁下应该清楚了,在C 语言中 *p++ 并没有什么含糊不清的地方。

至于位操作符,俺不觉得 Kernighan 和 Ritchie 先生有什么不对。
虽然移位等效于乘除,但很多时候移位并非用于计算,而是用于向端口输出串行数据。
关系运算的结果是逻辑值,所以优先级比位运算略高也说得过去。

-------------------------------------------------------------
编辑原因:修改排版。
mint
5楼-- · 2020-01-09 01:36
 精彩回答 2  元偷偷看……
runapp
6楼-- · 2020-01-09 05:45
没必要,随手查表,省的出错

一周热门 更多>