Skip to content

Side Effect & Sequence Point

cheyiliu edited this page Nov 24, 2014 · 7 revisions

引子

  • 问变量a的最后值是多少?
     	int a=0;
     	a = (++a)+(++a)+(++a)+(++a);
    

我的初步分析和验证

  • 做了4次前缀++, 我认为的结论是: 1+2+3+4=10
  • 验证
    • java,jdk1.7, 结果是10
    • c,gcc4.4.3,结果是11
    • c++,gcc4.4.3,结果是11

是不是有点懵了。。。

  • ...

赶紧查资料吧

  • C 语言标准对 副作用 和 序列点 的定义如下

Accessing a volatile object, modifying an object, modifying a file, or calling
a function that does any of those operations are all side effects, which are
changes in the state of the execution environment. Evaluation of an expression
may produce side effects. At certain specified points in the execution sequence
called sequence points, all side effects of previous evaluations shall be
complete and no side effects of subsequent evaluations shall have taken place. 翻译如下:

访问易变对象,修改对象或文件,或者调用包含这些操作的函数都是副作用,它们都会改变执行环境的状态。
计算表达式也会引起副作用。执行序列中某些特定的点被称为序列点。在序列点上,该点之前所有运
算的副作用都应该结束,并且后继运算的副作用还没发生。


* 在同一个序列点中,如果对某个变量或对象做了多次修改,那么这多次修改产生side effect的执行顺序是不能保证的
Sequence points also come into play when the same variable is modified more than   

once within a single expression. An often-cited example is the C expression i=i++,
which apparently both assigns i its previous value and increments i. The final value
of i is ambiguous, because, depending on the order of expression evaluation, the
increment may occur before, after, or interleaved with the assignment. The definition
of a particular language might specify one of the possible behaviors or simply say
the behavior is undefined. In C and C++, evaluating such an expression yields
undefined behavior.

这段话的含义是,在同一个序列点中,如果对某个变量或对象做了多次修改,那么这多次修改
产生side effect的执行顺序是不能保证的,那么i = i++这个语句就不能保证是i++这条语句先把
值写入到内存中,还是i =这条赋值语句先把值写入到内存中。


* 问题原因:标准规定,在两个序列点之间,一个对象所保存的值最多只能被修改一次。但是   
我们清楚可以看到,上面这个例子中,变量的值在两个序列点之间被修改了多次。这显然是错误的!   
这段代码在不同的编译器上编译可能会导致变量的值有所不同。or simply say the behavior is undefined.


# best practice
* 在两个Sequence Point之间,同一个变量的值只允许被改变一次。
* 仅有这一条原则还不够,例如a[i++] = i;的变量i只改变了一次,但结果仍是Undefined,因为等号左边改i的值,等号右边读i的值,到底是先改还是先读?这个读写顺序是不确定的。但为什么i = i + 1;就没有歧义呢?虽然也是等号左边改i的值,等号右边读i的值,但你不读出i的值就没法计算i + 1,那拿什么去改i的值呢?所以这个读写顺序是确定的。
* 如果在两个Sequence Point之间既要读一个变量的值又要改它的值,只有在读写顺序确定的情况下才可以这么写。
* Adding more sequence points is sometimes necessary to make an expression defined and to ensure a single valid order of evaluation.
* eg.
   ```
int a=0; a = (++a)+(++a)+(++a)+(++a);
可修改为
int a=0;
int a1 = ++a;
int a2 = ++a;
int a3 = ++a;
int a4 = ++a;
a = a1+a2+a3+a4;
   ```
* 编译时,gcc -Wsequence-point 或者gcc -Wall

# ref
* Side_effect, http://en.wikipedia.org/wiki/Side_effect_%28computer_science%29
* Sequence_point, http://en.wikipedia.org/wiki/Sequence_point
* http://akaedu.github.io/book/ch16s03.html
* http://www.oserror.com/language/317.html
* http://www.cnblogs.com/dong008259/archive/2011/12/14/2288068.html
* http://blog.csdn.net/bnufq/article/details/8953465
Clone this wiki locally