问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

【C语言】优先级,结合方向和执行顺序

发布网友 发布时间:2022-09-02 13:24

我来回答

1个回答

热心网友 时间:2023-10-11 19:57

K&R的书中一再强调"C is not a big language",当时看书的时候无法理解这句话的意思。现在我的理解是C标准本身的*比较小,留给程序员的空间较大。这样一来C中的而有些问题标准就没有给出限定,就会产生一些让人迷惑的地方。今天我遇到了一个这样的问题,解决这些问题有的时候看起来是“钻牛角尖”,好吧,我就是一个爱钻牛角尖的人。这里需要解决的问题是执行顺序的问题,先给出几个问题。

执行完这两个语句后i和j的值各是什么?(看着是不是很熟悉,上次笔试考C中是不是有这个呢)

执行完上述语句后,i和数组arry中的值是多少?

输出结果是什么?(来自于C Puzzle Book Operators 1.6 )
先把这几个问题放在这里,先思考下,下面将会解决他们。

C语言经典著作 “The C Programming Language” 中对于side effects的定义:

这里述说的side effect可以理解为一种“副作用”,这种作用是改变一个变量的值。
“C In Nutshell” 中关于side effects的定义:

相对于K&R中的定义这里使用了对于环境的改变,这应该更加准确。总结:side effects 就是程序中的实体产生的改变,这里所说的实体通常指变量。
赋值,自增,自减表达式会产生side effects,函数调用表达式也有可能产生side effects。

序列点(sequence points)是一种逻辑意义的点,它的意义在于,逻辑点前的副作用(side effects)都在这时生效。C标准中定义的序列点总共有三类,第一类是完全表达式(full expression);第二类是||,&&,?:和;第三类是函数调用,在所有的参数确定后、函数真正调用之前。

标准中规定了在前一个序列点前的副作用都会在前一个序列点后完成,但是标准没有规定两个序列点之间的副作用生效的顺序,不同的C语言实现的顺序可能不同。请注意这一点,这是所有问题产生的根本原因。如果两个序列点之间有超过两个的副作用作用在同一个实体上,这样不同的编译器产生的结果就不同,这种情况在标准中称为unspecified 。所以在实际应用中应该避免这种情况的出现,我把这一个原则称为为SS1。

是不是遵守了SS1原则就不会产生unspecified了呢?非也。可以设想这样一种情况:每一个实体(A)在两个序列点之间被两次使用,只有一次对这个实体本身产生副作用,另外一次被间接的用来产生副作用作用于另外一个实体(B)。在前面设想的这种情况下虽然符合SS1原则,但是我们会发现被间接用来产生副作用时,对于实体(B)产生的副作用肯定会跟实体(A)有关,但是这个实体(A)在这个序列点区间中有被副作用作用,那么我们就无法确定这个实体(A)的值了,从而实体(B)也就无法确定了。这里可以归纳为:在两个序列点之间,如果出现对一个实体的多次引用,并且只有一次会对该实体产生副作用(SS1),那么所有的这些引用都必须用来产生这个副作用 ,我把这一个原则称为SS2。只有同时遵守了SS1和SS2,写出的表达式才不是unspecified类型的。

可以清晰的看到标准中使用了两句话来概括这种问题,这正好对应于SS1,SS2原则。

下面给出更为具体的方法:
1)在一个表达式中最多只改变一个实体。
2)如果一个实体在一个表达式被改变,并且出现次数大于一次,请保证所有实体的出现都是为了产生这个“改变”。
例如: i = i+1;
3)如果不能遵守1),那么请保证改变的是不同的实体。
例如:c = *p++;
4)如果1)和2)都不能遵守,那么请使用序列点将表达式分开。
例如 : (c = getchar()) != EOF && c != ‘\n’;

C语言中组成程序的基本单位是表达式(expression),表达式是指用操作符(operator)和操作数(operand)连接起来的式子。C标准给出了最基本的操作符,通过这些操作符可以组成简单表达式,同样也可以通过复合产生复杂表达式。当一个表达式中出现多个操作符,多个操作数的时候,操作符合操作数是如何组合起来的呢?优先级和结合方向就是用来解决这个问题的,可以这么说,优先级和结合方向给出了一个表达式的含义,这只是说明了各个操作符和操作数是怎么聚合起来的。

仅仅依靠优先级和结合方向是无法确定一个复合表达式中对各个子表达式的求值顺序。标准中对于这点的规定是:
两个相邻的操作符的执行顺序由它们的优先级决定。如果它们优先级相同,它们的执行顺序由它们的结合性决定。除此之外,编译器可以自由决定任何顺序对表达式进行求值,只要它不违反逗号,&&,||和?:操作符所施加的*。

1)j = i++ + i++ + i++;
这个表达式违反了SS1,不同的编译器产生的结果可能不同。
2)arry[i] = i++;
这个表达式违反了SS2,不同的编译器产生的结果可能不同。
3)x = y = z = 1;
++x || ++y && ++z; PRINT(x, y, z);
&&的优先级比|| 的优先级高,所以:
++x || ++y && ++z 等效于++x || (++y && ++z)
这里就很容易犯错,会认为先执行++y && ++z 在执行++x || ( … ),这种观点是错误的,c中只对 逗号,、逻辑与 &&、
逻辑或 || 和 条件表达式规定了执行顺序,对于逻辑表达式方向是从左向右执行的。本例子中,先执行 ++x = 2,逻辑
或表达式被短路,++y && ++z没有执行,最后x = 2, y = 1, z = 1;

通过本课题的学习加深了对于c的理解,理解SS1,SS2原则。在实际应用中应该遵守“一条语句只做一件事的原则”。
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
国外留学有用吗 花钱出国留学有用吗 !这叫什么号 百万医疗赔付后是否可以续保 前一年理赔过医疗险还能续保吗? 医疗住院险理赔后还能购买吗? 女生多大后可以不在长身高? 如何不用软件把手机投屏到电脑上手机屏幕怎样投放到电脑上 战时拒绝、故意延误军事订货罪既遂的处罚? 战时故意延误军事订货罪处罚标准 护理心理学大学生结课论文1500字 护理安全隐患论文范文 关于护理心理学论文范文 护理专业本科毕业论文完整范文 天使爱美丽的剧情 逼上梁山精忠报国怒发冲冠梦笔生花这些故事的主人公分别是谁? 逼上梁上故事的主人公是谁 天竺草海娜粉有没有重金属 果酱一打开有一股气体冲出,吃起来有酒味,是不是变质了?? 天竺草染护发效果怎样 天竺草染发剂和海娜粉有区别吗? 天竺草和海娜花一样吗 我的联想笔记本电脑,电脑没声音。插上耳机音响就有声音。是什么坏了 沉香树苗如何种植 苹果6s的手机铃声怎么设置添加? 5升鑫城龙橄榄茶籽调和油多少钱一瓶 金浩茶籽橄榄食用调和油5升装的多少钱一瓶 福达坊茶籽橄榄调和油1.8升多少钱 记得申请邮箱怎样找回UC账号 物理治疗及康复设备有那些厂家? 破釜沉舟丶铁面无私丶完璧归赵望梅止渴丶逼上梁山的主人公是谁人 重阳节手抄报图片素材 2021九九重阳节手抄报素材 手抄报内容简短 ps4国行备份港服有保修吗 国行机还原了港服PSN信息,那还给保修么 买ps4是买国行,在港服备份好,还是直接买港服好? 逼上梁山读后感 稍就在文言文中的意思 有哪些含义 送东阳马生序原文翻译及作者 强酸.强碱.弱酸.弱碱有哪些 强酸 强碱有哪些 在高中阶段,有哪些酸是混合物,请详细,拜托了 酸中有哪些混合物 强酸有哪些? 自制凉皮加了酵母粉揉的面会成功吗? 下列成语中的主角是谁? 写日落的美景诗句 关于夕阳日落的诗句 电脑重装系统无法完成,系统提醒磁盘已满必须要释放600MB的空间,可C盘总共容量就150MB,急求个高手指导谢谢 小米4电信版怎么三清