side effect和Sequence points

1.C11中的side effect(副作用)

  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 in general includes both value computations and initiation of side effects. Value computation for an lvalue expression includes determining the identity of the designated object.

  访问一个易变目标、更改一个目标或文件、调用一个函数,这些操作都有副作用。副作用就是执行环境的状态的变化。计算一个表达式通常包含值的计算和副作用的启动。对于一个左值表达式,值计算包括确定指定目标的身份。

2.序列点

  1 The following are the sequence points described in 5.1.2.3:
  — Between the evaluations of the function designator and actual arguments in a function
  call and the actual call. (6.5.2.2).

  在函数运行和实参调用之间有序列点
  — Between the evaluations of the first and second operands of the following operators:
  logical AND && (6.5.13); logical OR || (6.5.14); comma , (6.5.17).

  在&&,||,逗号的第一和第二操作数之间有序列点
  — Between the evaluations of the first operand of the conditional ? : operator and
  whichever of the second and third operands is evaluated (6.5.15).

  在?:操作符的第一操作数和第二(第三)操作数之间有序列点
  — The end of a full declarator: declarators (6.7.6);

  在一个完整的声明结尾处有序列点
  — Between the evaluation of a full expression and the next full expression to be
  evaluated.

  在计算完一个完整的表达式和计算下一个完整的表达式之间有序列点。

  The following are full expressions:  

    an initializer that is not part of a compound literal (6.7.9);

    the expression in an expression statement (6.8.3);

    thecontrolling expression of a selection statement (if or switch) (6.8.4);

    the controlling expression of a while or do statement (6.8.5);

    each of the (optional) expressions of a for statement (6.8.5.3);

    the (optional) expression in a return statement (6.8.6.4).          

  — Immediately before a library function returns (7.1.4).

  在一个库函数返回之前的一刻有序列点
  — After the actions associated with each formatted input/output function conversion
  specifier (7.21.6, 7.29.2).

  在每一个格式化I/O函数的指定转化操作之后有序列点
  — Immediately before and immediately after each call to a comparison function, and
  also between any call to a comparison function and any movement of the objects
  passed as arguments to that call (7.22.5).
  在调用一个比较函数之前和之后的一刻有序列点,在任何调用比较函数和任何传递给函数的参数之间有序列点

3.例子:

  3.1

  int b = 5, ++b;

  因为","会产生序列点,所以","左边的表达式必须先求值,如果有副作用,副作用也会生效。然后才会继续处理","右边的表达式。

  3.2

  int a = 5;

  int b =  a++ > 5 ? 0:a;

  因为"?:"处有序列点,其左边的表达式必须先求值完毕。 a++ > 5在和5比较时,a并没有自增,所以表达式求值为FALSE。 因为"?"处的序列点,其左边表达式的副作用也要立即生效,即a自增1,变为6。 因为"?"左边的表达式求值为FALSE,所以三元操作符?:返回:右边的值a。 此时a的值是6,所以b的值是6。

  3.3

   int i = 1;
        i++;     /* i++是一个完整表达式 */
        i++ + 1; /* i++就不是一个完整的表达式,因为它是i++ + 1这个完整表达式的一部分 */

  3.4

  int i = 1; 

  i++, i++, i++;

  printf("%d\n", i);
  由于逗号有序列点,i=4;

  3.5

  int a = 10;
  int b = 0;
  if (b && a/b) 
  { /* some code here */ }

  因为&&支持短路操作,必须先将&&左边的表达式计算完毕,如果结果为FALSE,则不必再计算&&右边的表达式,直接返回FALSE。由于&&之前有序列点,会先判断b,b=0会结束判断,否则a/b会报错。

  3.6

  奇怪的C中给出的例子。

  int i = 3;

  int b = (++i)+(++i)+(++i);

  (++i)+(++i)+(++i)之间并没有序列点,它们的执行顺序如何呢? gcc编译后,先执行两个++i,把它们相加后,再计算第三个++i, 再相加。

  而Microsoft VC++编译后,先执行三个++i,再相加。 两者得到的结果不同,谁对谁错呢?谁也没有错。C标准规定:两个序列点之间的执行顺序是任意的。 当然这个任意是在不违背操作符优先级和结合特性的前提下的。 这个规定的意义是为编译器的优化留下空间。知道这个规定,我们就应该避免在一行代码中重复出现被递增的同一个变量, 因为编译器的行为不可预测。 试想如果 (++i)+(++i)+(++i)换成 (++a)+(++b)+(++c)(其中a、b、c是不同的变量), 不管++a,++b和++c的求值顺序谁先谁后,结果都会是一致的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值