搜索
bottom↓
回复: 109

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

  [复制链接]

出0入0汤圆

发表于 2017-4-6 11:36:12 | 显示全部楼层 |阅读模式
本帖最后由 TBG3 于 2017-4-6 11:46 编辑

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

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

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

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

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

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

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

第五条是 单目里面的优先度,和2,3,4里面的优先度是一样一样的,赋值里面的优先度也跟2,3是一样一样的。

阿莫论坛20周年了!感谢大家的支持与爱护!!

你熬了10碗粥,别人一桶水倒进去,淘走90碗,剩下10碗给你,你看似没亏,其实你那10碗已经没有之前的裹腹了,人家的一桶水换90碗,继续卖。说白了,通货膨胀就是,你的钱是挣来的,他的钱是印来的,掺和在一起,你的钱就贬值了。

出0入0汤圆

发表于 2017-4-6 11:43:06 | 显示全部楼层
本帖最后由 babysnail 于 2017-4-6 11:45 编辑

第三写错了, 搞错了,是后面的写错了

出0入0汤圆

 楼主| 发表于 2017-4-6 11:45:02 | 显示全部楼层
babysnail 发表于 2017-4-6 11:43
第三写错了, 应该是逻辑运算优先于关系运算

你这是美好的期望啊。

出0入0汤圆

发表于 2017-4-6 11:47:35 | 显示全部楼层
优先级从上到下,然后看结合方向,不好记。顺便再看看
运算符     解释                           结合方式
() [] -> . 括号(函数等),数组,两种结构成员访问 由左向右
! ~ ++ -- + -  * & (类型) sizeof否定,按位否定,增量,减量,正负号,
间接,取地址,类型转换,求大小          由右向左
* / %    乘,除,取模                   由左向右
+ - 加,减                              由左向右
<< >> 左移,右移                         由左向右
< <= >= > 小于,小于等于,大于等于,大于 由左向右
== != 等于,不等于                      由左向右
& 按位与                                由左向右
^ 按位异或                              由左向右
| 按位或                                由左向右
&& 逻辑与                               由左向右
|| 逻辑或                               由左向右
? : 条件                                由右向左
= += -= *= /=  &= ^= |= <<= >>=各种赋值 由右向左
, 逗号(顺序) 由左向右

出10入0汤圆

发表于 2017-4-6 11:51:37 来自手机 | 显示全部楼层
乘除大于加减,别的用括号。

出0入442汤圆

发表于 2017-4-6 11:55:00 来自手机 | 显示全部楼层
事实证明,不加括号是no zuo no die。实践表明,100个计算错误里面有97个是不用括号造成的。

出0入0汤圆

发表于 2017-4-6 12:08:40 | 显示全部楼层
加括号最好

出0入0汤圆

 楼主| 发表于 2017-4-6 12:15:06 | 显示全部楼层
wye11083 发表于 2017-4-6 11:55
事实证明,不加括号是no zuo no die。实践表明,100个计算错误里面有97个是不用括号造成的。 ...

说明你记得很不清楚。

出0入0汤圆

发表于 2017-4-6 12:21:12 来自手机 | 显示全部楼层
压根不记!写代码规定必须括号写死!用误解可能的分开写

出0入0汤圆

发表于 2017-4-6 12:21:38 | 显示全部楼层
括号成员第一;        //括号运算符[]() 成员运算符.  ->

全体单目第二;        //所有的单目运算符比如++、 --、 +(正)、 -(负) 、指针运算*、&

乘除余三,加减四;   //这个"余"是指取余运算即%

移位五,关系六;    //移位运算符:<< >> ,关系:> < >= <= 等

等于(与)不等排第七;    //即== 和!=

位与异或和位或;    //这几个都是位运算: 位与(&)异或(^)位或(|)   

"三分天下"八九十;  

逻辑或跟与;            //逻辑运算符:|| 和 &&

十二和十一;            //注意顺序:优先级(||)  底于 优先级(&&)

条件高于赋值,        //三目运算符优先级排到13 位只比赋值运算符和","高

逗号运算级最低!    //逗号运算符优先级最低

出0入0汤圆

发表于 2017-4-6 12:24:28 来自手机 | 显示全部楼层
坛友不是不记优先级,而是为了程序的可读性和不出错都是加括号,毕竟做项目不是考计算机二级

出0入0汤圆

发表于 2017-4-6 12:24:57 | 显示全部楼层
我从来不记,一般加括号

出130入20汤圆

发表于 2017-4-6 12:31:10 | 显示全部楼层
不要吝啬括号,自己不会搞错,也方便别人维护

出0入25汤圆

发表于 2017-4-6 12:33:25 | 显示全部楼层
()                              

出0入131汤圆

发表于 2017-4-6 12:42:01 | 显示全部楼层
我一般不用太复杂的表达式,太复杂了 就分多行。

出0入0汤圆

发表于 2017-4-6 12:47:37 | 显示全部楼层
没关心过这个优先级的问题。。。

出0入0汤圆

发表于 2017-4-6 13:19:44 | 显示全部楼层
不会写代码的路过

出0入0汤圆

发表于 2017-4-6 13:39:53 来自手机 | 显示全部楼层
赞同13楼,不要吝啬括号

出0入0汤圆

发表于 2017-4-6 13:47:17 | 显示全部楼层
可以加括号谁还会在乎优先级。保险又易懂。

出0入0汤圆

发表于 2017-4-6 13:47:51 | 显示全部楼层
yangyongwen 发表于 2017-4-6 12:24
我从来不记,一般加括号

相同                     

出0入25汤圆

发表于 2017-4-6 13:47:57 | 显示全部楼层

不急优先级,万一再学个C#什么的优先级不全记混了,还是括号好!!

出0入0汤圆

发表于 2017-4-6 13:57:46 | 显示全部楼层
TBG3 发表于 2017-4-6 12:15
说明你记得很不清楚。

不是记不清楚,而是根本就都不记得,括号搞定一切。

出0入0汤圆

发表于 2017-4-6 14:03:49 | 显示全部楼层
看图比较明白



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出280入168汤圆

发表于 2017-4-6 14:08:01 | 显示全部楼层
直接用 ( ) , 硬背没必要 ...

出0入0汤圆

发表于 2017-4-6 14:12:25 | 显示全部楼层
用(),记不清
还有不用复杂的运算语句,数目多了就拆分成多个语句

出0入0汤圆

发表于 2017-4-6 14:13:29 | 显示全部楼层
wye11083 发表于 2017-4-6 11:55
事实证明,不加括号是no zuo no die。实践表明,100个计算错误里面有97个是不用括号造成的。 ...

怒赞!!!!!!

出0入0汤圆

发表于 2017-4-6 14:15:33 来自手机 | 显示全部楼层
就不应该知道默认的优先级是怎么样的 然后大家就都加括号 万事大吉

出0入17汤圆

发表于 2017-4-6 14:19:32 | 显示全部楼层
一个简单的  *p++  ,你这5条就不管用。

出0入0汤圆

发表于 2017-4-6 14:26:06 | 显示全部楼层
TBG3 发表于 2017-4-6 12:15
说明你记得很不清楚。

孔乙己倒是记得很清楚,有啥用呢?为了自己也为了别人,必须用括号啊

随便哪个大公司的代码规范都要求可读性第一,括号万能啊

出0入0汤圆

发表于 2017-4-6 14:32:03 来自手机 | 显示全部楼层
管他呢,如果认为要优先级高的,我就加括号!

出0入93汤圆

发表于 2017-4-6 14:41:06 | 显示全部楼层
  1. *pDst++ = *pSrc++;
复制代码
您给解释下到底怎么回事,自增就他娘的一个坑,根本就不按套路出牌

出0入0汤圆

发表于 2017-4-6 15:35:59 来自手机 | 显示全部楼层
除了最基本的,其它一律用括号

出0入4汤圆

发表于 2017-4-6 15:50:29 | 显示全部楼层
都是直接或者间接深受谭浩强毒害,长篇大论代码效率,各种钻牛角尖的问题,跟茴香豆有几种写法一个逻辑。代码里加几个括号能死么?提高了那点一点点效率,却牺牲了代码的可读性。

出0入58汤圆

发表于 2017-4-6 15:57:31 | 显示全部楼层
我从来不记,向来都是加括号,与人方便于己方便。

出0入0汤圆

发表于 2017-4-6 17:24:58 | 显示全部楼层
记这玩意干嘛 上括号啊

出0入10汤圆

发表于 2017-4-6 17:27:25 来自手机 | 显示全部楼层
都是加括号

出0入0汤圆

 楼主| 发表于 2017-4-6 17:37:27 | 显示全部楼层
wajlh 发表于 2017-4-6 15:50
都是直接或者间接深受谭浩强毒害,长篇大论代码效率,各种钻牛角尖的问题,跟茴香豆有几种写法一个逻辑。代 ...

代码可读性对外行而言不存在。

出0入0汤圆

 楼主| 发表于 2017-4-6 17:40:14 | 显示全部楼层
对很多人而言,C是吃饭的家伙。

如果不能了解细节,精确掌握,不过是得过且过而已。

将来淘汰的,就是这种。就像当年东北国企关门,八级钳工照样前途无限;而熟练工就很惨。

建议诸位不要去做熟练工。

出0入0汤圆

发表于 2017-4-6 17:47:56 来自手机 | 显示全部楼层
头大,直接加括号

出0入25汤圆

发表于 2017-4-6 18:40:24 来自手机 | 显示全部楼层
TBG3 发表于 2017-4-6 17:40
对很多人而言,C是吃饭的家伙。

如果不能了解细节,精确掌握,不过是得过且过而已。

有这时间研究点儿更有用的不好?比如数字信号处理、USB、

出0入198汤圆

发表于 2017-4-6 18:47:50 | 显示全部楼层
我的口诀:算移比位逻(优先级从高到低)

上学时候总结的,这么多年一直用它。

出0入8汤圆

发表于 2017-4-6 18:52:41 | 显示全部楼层
sunnydragon 发表于 2017-4-6 18:47
我的口诀:算移比位逻(优先级从高到低)

上学时候总结的,这么多年一直用它。 ...

我没有口诀,
不特意记,多数靠括号。

出10入23汤圆

发表于 2017-4-6 19:20:16 来自手机 | 显示全部楼层
wajlh 发表于 2017-4-6 15:50
都是直接或者间接深受谭浩强毒害,长篇大论代码效率,各种钻牛角尖的问题,跟茴香豆有几种写法一个逻辑。代 ...

加括号影响效率?

出0入93汤圆

发表于 2017-4-6 19:35:07 | 显示全部楼层
wajlh 发表于 2017-4-6 15:50
都是直接或者间接深受谭浩强毒害,长篇大论代码效率,各种钻牛角尖的问题,跟茴香豆有几种写法一个逻辑。代 ...

事实上根本就没有代码效率的提高,反而是可读性大大降低了。谭浩强毕竟是那个年代的人,他当时出的书应该无可厚非,在这个奇葩的国度用来应付考试大概是极好的,但直接用于生产环境,大概是有点特立独行吧。
我就被a+++++b为难过,后来知道了,尼玛违反MISRA C的拿来折腾啥啊,出题人有病吧。
还有更有病的,&p是取p的地址,问&&p是啥,是你麻痹,这个是逻辑与好不,编译都有语法错误。
还有位运算,尼玛C系列语言与人们普遍认知是反的,居然还有人当作圣经,真是哔了狗了,移位不应该和乘除一个等级吗,位运算不应该比==、!=优先级高吗。好吧,我承认我Delphi中毒太深了。

我只想说,不用括号,能节省几个字节的硬盘空间?

出0入8汤圆

发表于 2017-4-6 20:14:19 | 显示全部楼层
takashiki 发表于 2017-4-6 19:35
事实上根本就没有代码效率的提高,反而是可读性大大降低了。谭浩强毕竟是那个年代的人,他当时出的书应该 ...

位运算的优先级,确实有点那个,
如果不加括号,我觉得很多人曾在这边掉进坑里过。

出0入8汤圆

发表于 2017-4-6 20:15:21 来自手机 | 显示全部楼层
zouzhichao 发表于 2017-4-6 19:20
加括号影响效率?

其实我都是直接写机器码
写成C语言还要编译
效率太低了

出0入198汤圆

发表于 2017-4-6 20:41:21 | 显示全部楼层
security 发表于 2017-4-6 18:52
我没有口诀,
不特意记,多数靠括号。

毕竟有些时候也得读读别人的代码嘛。

出0入166汤圆

发表于 2017-4-6 20:51:48 来自手机 | 显示全部楼层
TBG3 发表于 2017-4-6 12:15
说明你记得很不清楚。

有时候加括号能增强可读性,还避免错误。
非要搞复杂的优先度,你以为是考试做题呢。
有点像孔乙己的茴有几种写法一样

出0入0汤圆

发表于 2017-4-6 20:53:46 来自手机 | 显示全部楼层
wajlh 发表于 2017-4-6 15:50
都是直接或者间接深受谭浩强毒害,长篇大论代码效率,各种钻牛角尖的问题,跟茴香豆有几种写法一个逻辑。代 ...

不加括号能提高效率?

出0入0汤圆

发表于 2017-4-6 21:02:08 | 显示全部楼层

()                              

出0入22汤圆

发表于 2017-4-6 21:05:31 | 显示全部楼层
takashiki 发表于 2017-4-6 14:41
您给解释下到底怎么回事,自增就他娘的一个坑,根本就不按套路出牌

指针是 最高优先级的。

这个表达式 经常用的。

其余的能加括号就加括号。

不同的编译器 对运算符的先后都可能不一样。如果你开了优化,结果你永远都想不到。

出0入0汤圆

发表于 2017-4-6 21:25:32 | 显示全部楼层
基本上不记,遇到多个运算就是()对待!简单粗暴

出0入93汤圆

发表于 2017-4-6 21:44:45 | 显示全部楼层
lixin91985 发表于 2017-4-6 21:05
指针是 最高优先级的。

这个表达式 经常用的。

事实上,他这个表才是正确的,但是从这个表上直接推算根本和我们想象的大相径庭。
聪明的编译器可能会编译成:*pDst = *pSrc; pDst ++; pSrc ++;
但是符合标准的编译器(完全没有优化)应该编译成这个样子:
加括号的等价:*(pDst++) = *(pSrc++);
展开为:
  1. pTempDst = pDst;                          // 后缀自增、自减会产生临时变量(寄存器变量)
  2. pDst ++;
  3. pTempSrc = pSrc;
  4. pSrc ++;
  5. *pTempDst = *pTempSrc;
复制代码


很遗憾,您的回答错误。如果指针是最高优先级,那么*pDst++会等价于 (*pDst)++,显然不是你想要的。
我只想说,后缀自增自减其实是有坑的,TM的坑还不浅!

出0入0汤圆

发表于 2017-4-6 22:43:20 | 显示全部楼层
从来不记得,我都是直接加括号,哈哈

出0入0汤圆

发表于 2017-4-6 23:04:22 | 显示全部楼层
takashiki 发表于 2017-4-6 21:44
事实上,他这个表才是正确的,但是从这个表上直接推算根本和我们想象的大相径庭。
聪明的编译器可能会编 ...

自增自减坑无比啊!!!!!

出0入0汤圆

发表于 2017-4-7 06:45:27 来自手机 | 显示全部楼层
曾经掉在位运算跟比较的坑里

出0入0汤圆

发表于 2017-4-7 08:55:17 | 显示全部楼层
这个话题估计楼层高,自己确实也被坑过

出0入0汤圆

 楼主| 发表于 2017-4-7 09:03:19 | 显示全部楼层
XIVN1987 发表于 2017-4-6 18:40
有这时间研究点儿更有用的不好?比如数字信号处理、USB、

要想有长进,必须精益求精。我不信有人能忙到连记优先度的时间都没有。

出0入0汤圆

 楼主| 发表于 2017-4-7 09:04:22 | 显示全部楼层
sunnydragon 发表于 2017-4-6 18:47
我的口诀:算移比位逻(优先级从高到低)

上学时候总结的,这么多年一直用它。 ...

这个比我的更精炼。

出0入0汤圆

发表于 2017-4-7 09:06:33 | 显示全部楼层
没意义,多用几个括号就解决了。还是好好学学编程思路

出0入0汤圆

 楼主| 发表于 2017-4-7 09:07:26 | 显示全部楼层
takashiki 发表于 2017-4-6 19:35
事实上根本就没有代码效率的提高,反而是可读性大大降低了。谭浩强毕竟是那个年代的人,他当时出的书应该 ...

有个东西叫做读代码的效率。

那些认为括号可读性好的人,忽视了一个问题:对于精通优先度的人而言,根本提高不了效率。

而一边读代码一边反复查书的人,要用多少时间花在查书上呢?

出0入4汤圆

发表于 2017-4-7 09:13:49 | 显示全部楼层
TBG3 发表于 2017-4-6 17:40
对很多人而言,C是吃饭的家伙。

如果不能了解细节,精确掌握,不过是得过且过而已。

熟练掌握的同学更应该写代码的时候加括号了,要准确的表达自己的意思,不要摸棱两可让别人去猜。

出0入4汤圆

发表于 2017-4-7 09:14:02 | 显示全部楼层

你这太懒了,直接复制我的截图。

http://baike.baidu.com/link?url= ... fHLI4g4d7CyYlm1QX__

出0入93汤圆

发表于 2017-4-7 09:14:14 | 显示全部楼层
TBG3 发表于 2017-4-7 09:07
有个东西叫做读代码的效率。

那些认为括号可读性好的人,忽视了一个问题:对于精通优先度的人而言,根本 ...


精通优先度的LZ,请解释下我31楼的问题,不要采用我55楼的回答。作为一个精通优先度的人,您一定是看不上我这个答案的。
我记性差,我只知道优先级是有坑的,我会尽力避免掉坑里。

出0入93汤圆

发表于 2017-4-7 09:15:56 | 显示全部楼层
本帖最后由 takashiki 于 2017-4-7 09:25 编辑
TBG3 发表于 2017-4-7 09:07
有个东西叫做读代码的效率。

那些认为括号可读性好的人,忽视了一个问题:对于精通优先度的人而言,根本 ...


然后请您给解释下 a  = b[a] + a++;的优先级关系,到底先算b[a]还是先算a++。
再比如:a = 1, a = a++ + a++ + a++; 请求出a。如果您能得出一个确定的标准答案,那么我服你,你大概可以制定C语言标准了。这个是规矩的“未定义行为”,不同的编译器有不同的实现。

出0入0汤圆

 楼主| 发表于 2017-4-7 09:16:14 | 显示全部楼层
wicy001 发表于 2017-4-6 14:19
一个简单的  *p++  ,你这5条就不管用。

知道++和*的优先度,就很好算了。觉得难就一个原因:概念不清楚。

++优先于*

后置++ 则先取p

出0入0汤圆

 楼主| 发表于 2017-4-7 09:23:33 | 显示全部楼层
takashiki 发表于 2017-4-7 09:14
精通优先度的LZ,请解释下我31楼的问题,不要采用我55楼的回答。作为一个精通优先度的人,您一定是看不上 ...

已经解释过了。

++ --前置与后置不在优先度里面。

++ -- 是数学运算,优先于取内容的*, 取地址的&。

++ -- 前置,则取运算后的变量值;++ -- 后置,则在表达式中取变量原来的值。

出0入0汤圆

 楼主| 发表于 2017-4-7 09:26:34 | 显示全部楼层
takashiki 发表于 2017-4-7 09:15
然后请您给解释下 a  = b[a] + a++;的优先级关系,到底先算b[a]还是先算a++。

这个更简单。

其实你了解到处理器是顺序执行的,就可以了。

出0入93汤圆

发表于 2017-4-7 09:31:08 | 显示全部楼层
TBG3 发表于 2017-4-7 09:23
已经解释过了。

++ --前置与后置不在优先度里面。

嗯,好吧。
我又编辑了下,加入了“再比如:a = 1, a = a++ + a++ + a++; 请求出a”。至少我在不同的编译器下面得出的结果是不同的。自增的副作用实在是可恶,这样的问题很无聊,但是谭浩强的书里面都是都是这样的代码。我一般都是按MISRA规矩独立写一句的,根本不管什么优先级问题。

出100入0汤圆

发表于 2017-4-7 09:35:19 | 显示全部楼层
()
还能多算代码工作量!

出0入93汤圆

发表于 2017-4-7 09:38:12 | 显示全部楼层
TBG3 发表于 2017-4-7 09:26
这个更简单。

其实你了解到处理器是顺序执行的,就可以了。

你倒是算出个结果出来啊。
  1. int a = 0;
  2. int b[] = {0, 1, 2};
  3. a = b[a] + a++;
复制代码

你算出来a是等于0还是等于1啊,不同的编译器会给出不同的结果哦,我看看您属于哪一类?

我在VC++下算出来等于1,在TCC下面算出来等于0。精通优先级的LZ,您算出来等于多少?

出0入0汤圆

 楼主| 发表于 2017-4-7 09:39:56 | 显示全部楼层
takashiki 发表于 2017-4-7 09:31
嗯,好吧。
我又编辑了下,加入了“再比如:a = 1, a = a++ + a++ + a++; 请求出a”。至少我在不同的编译 ...



后置是非常安全的。

后置要在表达式计算完之后,再自增。这在C里面定义的非常清楚。

你的这个表达式,可能混淆在于 a.

a= a++ + a++ +a++;

在这个算式里面,编译器是处理

a= 3;

a++;

a++ ;

a++;

还是处理

a++;

a++;

a++;

a=3;

这个好像的确有歧义。

但是,如果算式是这样的;

a=1; b = a++ + a++ + a++;

那b铁定是3.

出0入0汤圆

 楼主| 发表于 2017-4-7 09:41:47 | 显示全部楼层
takashiki 发表于 2017-4-7 09:38
你倒是算出个结果出来啊。
你算出来a是等于0还是等于1啊,不同的编译器会给出不同的结果哦,我看看您属于 ...

这个已经解释过了。

a =  a++; 不同的编译器会产生歧义。

出0入93汤圆

发表于 2017-4-7 09:46:12 | 显示全部楼层
TBG3 发表于 2017-4-7 09:39
后置是非常安全的。

后置要在表达式计算完之后,再自增。这在C里面定义的非常清楚。

很可惜,您的答案不对哦。。
tcc算出来b = 6,不是铁定的3哦。

出0入93汤圆

发表于 2017-4-7 09:47:59 | 显示全部楼层
补充图片:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2017-4-7 09:52:23 | 显示全部楼层
而真正在应用中,出问题的反而是这个(一般不会遇到a=a++;不会这么写):
x=1;
y = x +(++x);
是先算++x呢,还是后算呢? C也没有定义清楚。

但是 y=x+++x; 铁定是 y = (x++)+x; 因为编译器采用贪婪原则,能多处理,就多处理。所以 a+++++b, 是先两个++ ,最后才是 + 。

出0入0汤圆

 楼主| 发表于 2017-4-7 09:58:16 | 显示全部楼层

我只能说它不符合规范。

出0入93汤圆

发表于 2017-4-7 10:13:06 | 显示全部楼层
TBG3 发表于 2017-4-7 09:58
我只能说它不符合规范。

这个答案很好,很强大。
tcc是属于GCC,因为它小,我以我爱用。你用GCC编译,得出的结论估计是一样的。GCC不规范?或许吧……
针对这样的代码,我只说,这个代码是不符合MISRA规范的,但是是符合C语言规范的。MISRA不允许有歧义的语句,所以,我是不会写这样的代码的。

打开我的Chrome,按下F12,开启Javascript调试,这个优先级啥的全部都继承自C,看看它怎么说吧:
谷歌你傻了?怎么就选了不规范的当参照呢?

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2017-4-7 10:14:27 | 显示全部楼层
还是习惯加括号。

出0入0汤圆

 楼主| 发表于 2017-4-7 10:17:28 | 显示全部楼层
中国的历史里面,逻辑一直没有发展起来。可以这么说:我们不太严谨。我们又有文学传统,用尽量少的词汇表达尽量多的意思。在文学上,这是好的。

但是在编程语言里面,这个东西叫做二义性。

就是一个语句里面有多种意思。这是编程语言竭力想阻止的。

一个语句就应该明白无误的是一个意思。

++ -- 会造成二义性。所以,用++ -- 尽量减少二义性。

各种规范已经很严谨了,但是再严谨的规范,也会产生二义性。

更何况,这世界上有很多不遵守规范的东西存在。

所以,熟悉规范,熟悉你的编译器,竭力避免二义性的产生。

因为程序是个很严谨的东西,一点点不同,最终会导致结果的大不同。

出0入93汤圆

发表于 2017-4-7 10:40:23 | 显示全部楼层
TBG3 发表于 2017-4-7 10:17
中国的历史里面,逻辑一直没有发展起来。可以这么说:我们不太严谨。我们又有文学传统,用尽量少的词汇表达 ...

我是SB,又把你的代码在Keil MDK下跑了一遍,一个是优化等级0,一个是优化等级3:
大概优化等级3是符合规范的,优化等级0是不符合规范的吧。
我的意思其实很简单,不要被各种不确定因素所束缚(优先级、未定义行为)。其实C规范就是非常非常不严谨的,想要严谨,你可以参考下ADA系列语言(Pascal/Delphi、VHDL等等),写得非常严谨而繁琐,一旦有歧义(语言本身的歧义很少了,主要是函数重载类型包含)编译器就会抱怨报错。但是C系列不会,他会按自己的理解去完成,结果吃亏的是码农自己。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2017-4-7 11:18:37 | 显示全部楼层
本帖最后由 TBG3 于 2017-4-7 11:25 编辑
takashiki 发表于 2017-4-7 10:13
这个答案很好,很强大。
tcc是属于GCC,因为它小,我以我爱用。你用GCC编译,得出的结论估计是一样的。GC ...


我用了两种编译器,一种是keil, 另外一种是 MPLAB X.

keil 结果和你的一样,都是a=4, b=6;

而mplab x 上,却是b=3; 不知道哪种符合C的规范。让我先查一查吧。

再加:我的这两个结果里面,优化程度都是0.


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2017-4-7 11:24:54 | 显示全部楼层
takashiki 发表于 2017-4-7 10:40
我是SB,又把你的代码在Keil MDK下跑了一遍,一个是优化等级0,一个是优化等级3:
大概优化等级3是符合规 ...

我同意你后半句:

C本身不严谨。(其实相对于国人的不严谨性,C已经非常非常严谨了)。

实际上,编程语言作为人类的语言,必然有不严谨性。

但是程序目前必须有确定的结果。将来或许程序可以有不确定的结果。

但是,就目前而言,程序必须有确定性。所以,必须清楚了解规范,了解编译器的具体行为,在编程时, 才能尽量减少这种二义性。才能有一个确定的结果。

出0入0汤圆

发表于 2017-4-7 11:27:22 | 显示全部楼层
看了各位大神的回贴,老衲中午多点了两道菜和一碗大米饭
     

出0入0汤圆

 楼主| 发表于 2017-4-7 11:30:24 | 显示全部楼层
a挡住了,重传。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2017-4-7 11:33:33 | 显示全部楼层
看来楼主没遇到过不加括号在各种编译器下结果都不同。。。

出0入0汤圆

 楼主| 发表于 2017-4-7 11:40:36 | 显示全部楼层
huangqi412 发表于 2017-4-7 11:33
看来楼主没遇到过不加括号在各种编译器下结果都不同。。。

符号优先度是没有疑问的,不会有混淆的结果。

后面的讨论就很深入了。
前置后置++--是会有不同的。

有时候,甚至加括号都没有用! 不要以为括号万能。

比如
*p++ 和 *(p++)

所以,我在编程时,也的确如takashiki所言,一般都是把++ -- 单独弄出来。

另外,takashiki是日本人吗? 没别的意思,我认为现在日本社会大致上实现了东亚文明的理想。但是还是比不过西方人。

出0入42汤圆

发表于 2017-4-7 14:05:19 | 显示全部楼层
编了不少代码,进了无数坑,发现写代码和开车一样,想不翻车必须随时做到3个字:不要浪!

具体的说,就是:

1. 记一些常用运算符的优先级,其余一律用括号。
这没什么low的,括号除了有指定优先级的作用外,还能反映作者的思路。括号太多了怎么办?分行写,或者写成宏。分行使过程更清晰,宏可读性更高,更方便维护。

2. 不要低估了编译器的优化能力,充分利用它。
写一些没有歧义的代码,优化的事让编译器去做吧,程序员要做的,是写出逻辑上正确,并且方便阅读和交流的代码。

3. 不要有任何违和感。
代码不开优化没问题,开了优化就不正常了,那么是关优化还是改代码? 关优化几秒钟就解决了,改代码也许需要几小时。但这几小时,可以避免将来某个严重bug爆发带来的重大损失。

4. 综合考虑效率,不要过度抠细节
有两层意思,一是在程序运行效率和开发/维护效率之间找平衡点,二是重点优化影响系统性能的瓶颈部分。

5...

唉。。说多了都是泪

出0入0汤圆

 楼主| 发表于 2017-4-7 14:22:59 | 显示全部楼层
wshtyr 发表于 2017-4-7 14:05
编了不少代码,进了无数坑,发现写代码和开车一样,想不翻车必须随时做到3个字:不要浪!

具体的说,就是 ...

你说的这些都很对。
你说的这些,都要评估。而评估时重要的一点,就是足够信息,也就是细节。

出0入0汤圆

发表于 2017-4-8 08:18:37 来自手机 | 显示全部楼层
我就记个大概,算术移位关系逻辑。

出0入0汤圆

发表于 2017-4-8 13:31:18 | 显示全部楼层
好记性不如圆括号

出0入0汤圆

发表于 2017-4-8 17:58:33 | 显示全部楼层
我对10楼进行了整理,方便记忆:

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

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

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

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

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

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

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

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

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

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

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

第12优先级:        逗号运算符最低。例如:,(逗号)

出0入0汤圆

发表于 2017-4-8 22:17:28 | 显示全部楼层
本帖最后由 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 先生有什么不对。
虽然移位等效于乘除,但很多时候移位并非用于计算,而是用于向端口输出串行数据。
关系运算的结果是逻辑值,所以优先级比位运算略高也说得过去。

-------------------------------------------------------------
编辑原因:修改排版。

出0入0汤圆

发表于 2017-4-8 22:40:30 | 显示全部楼层
炫技可以,工程严重避免,因为需要可控,降低门槛

出0入0汤圆

发表于 2017-4-9 06:18:55 来自手机 | 显示全部楼层
没必要,随手查表,省的出错

出140入115汤圆

发表于 2017-4-9 14:43:05 | 显示全部楼层
从头看到尾,还是加()

出0入0汤圆

发表于 2017-4-9 17:31:12 | 显示全部楼层
在单独一条语句和for语句中会用到 i++;
在查表语句中会用到 table[i++]和  table[--i]。

出280入168汤圆

发表于 2017-4-10 05:06:10 来自手机 | 显示全部楼层
我解决不同的问题时,经常性使用不同的编程语言,若靠死记硬背早就脑袋炸裂了 …… 解决问题的要点在于方式方法,编程语法都是毛毛雨,临时翻一下手册就行了,甚至按一下 F1 就啥都解决了。想知道我用哪些编程语言吗?各种内核的汇编、甚至直接使用6502的机器代码(当然现在早忘光了)、c、c++、c#、vba、javascirpt、squirrel。用的比较多的是c++,解决大问题的时候,它是最便捷的。解决小问题,什么顺手用什么。别以为 basic 语言很弱,我在比小霸王学习机还老的学习机上写过 6502 的反汇编,录程序靠磁带。在 286 上用 x86 的宏汇编写出 68000 的反汇编工具,老同志们还记得那个行编辑器吗?还在 win95 上用 Borland c++ 3.0 写出可以聘美街机的空战游戏,因依赖太多的硬件操作,结果只能在本机运行,别人拷回家都是黑屏 …… 所以,我觉得不管什么工具能用到纯熟就是最好的。通往一个目标的路可能有千百条,但没必要每条路都要走一遍,走最熟悉最省力的路既方便自己,也方便跟随你的其他人。

出0入0汤圆

发表于 2017-4-10 07:53:44 来自手机 | 显示全部楼层
本帖最后由 liugang1986 于 2017-4-10 07:56 编辑

楼主你是不是换 id 了?以前遇到过一个叫  tgb2还是 tbg2  的是你吗?
          编辑原因 修改错别字。

出0入0汤圆

发表于 2017-4-10 08:34:59 | 显示全部楼层
一直不去记,加括号的路过
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-10-2 20:18

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表