******副作用:
指的是对数据对象(http://blog.csdn.net/qq_37385726/article/details/62896617)或文件的修改。
对于计算机来说,函数也好,表达式也好,语句也好(关于什么是表达式,什么是语句请戳:http://blog.csdn.net/qq_37385726/article/details/62897923)它们的主要目的就是返回值,但是对于人来说,调用函数,写语句,写表达式的主要目的却是利用它的副作用。
eg.关于a=3+7这个表达式,计算机的主要目的是它的返回值,即左值的值10,但是我们人的主要目的却是计算机称为的副作用,即将10赋给变量a.
******序列点:
指的是程序执行的点,在该点上,所有的副作用都在进入下一步之前发生。
那么哪些符号会生成序列点呢?
",
"会生成序列点。
",
"用于把多条语句拼接成一条语句。 例如:
int b = 5;
++ b;
可由",
"拼接成
int b = 5, ++b;
因为",
"会产生序列点,所以",
"左边的表达式必须先求值,如果有副作用,副作用也会生效。然后才会继续处理",
"右边的表达式。
&&
和||
会产生序列点
逻辑与 &&
和逻辑或 ||
会产生序列点。
因为&&
支持短路操作,必须先将&&
左边的表达式计算完毕,如果结果为false
,则不必再计算&&
右边的表达式,直接返回false
。
||
和&&
类似。
?:
中的"?
"会产生序列点
三元操作符 ?:
中的"?
"会产生序列点。 如:
int a = 5;
int b = a++ > 5? 0 : a;
b
的结果是什么?因为"?
"处有序列点,其左边的表达式必须先求值完毕。 a++ > 5
在和5比较时,a
并没有自增,所以表达式求值为false
。 因为"?
"处的序列点,其左边表达式的副作用也要立即生效,即a
自增1,变为6。 因为"?
"左边的表达式求值为false
,所以三元操作符?:
返回:
右边的值a
。 此时a
的值是6,所以b
的值是6。
还有“一个完整的表达式的结束”也是序列点
一个完整的表达式的结束:指的是这个表达式不是另一个更大的表达式的子语句。
===================================================================================
有了上面关于序列点的只是,我们就不难理解以下的这种情况了。
eg.y=(x++)+(x++);
这个是一个未定义行为,因为虽然自增的优先级被规定为大于+,但是计算机并没有规
定到底先执行哪一个x++,这就带来了一个未定义的问题,我们知道一个完整的表达式
的结束是一个序列点,也就是对于这个表达式而言,(x++)+(x++)是要在它的末尾才
是这个语句开始执行的地方,所以你不知道计算机是在执行了哪一个x++后再执行下一
个,又或者说是先用原来的x以后,再对这个x进行两次的自增,这就是我们所说的未定
义行为。
还有很多这样的例子:num*num++ 这就是未定义的,计算机没有指定先执行哪一个
子表达式,所以就带来了像上面所说的未定义行为的问题。