C 语言基本概念----再议副作用

C 语言基本概念----副作用icon-default.png?t=M85Bhttp://mp.weixin.qq.com/s?__biz=MzIyNDQyMzQ5Ng==&mid=2247489877&idx=1&sn=3a39a8204f80f475905070858b94d490&chksm=e80e6272df79eb6483e10db9aecfa09c7ee16cde2a974c934b7154e34b28bd888b91e105d6ab&scene=21#wechat_redirect一文中留有2个思考题,其中第一个思考题是:

思考1:上面程序中的表达式 k=++j+i+++j对吗?它是否也存在未定义行为?

我们用程序来验证。

#include 
int main(void)
{
  int i,j,k;
  i=1;
  j=2;
  k=++j+i+++j;
  printf("i=%d, j=%d, k=%d\n",i,j,k);
  return 0;
}

上面这个程序在VC++6.0和Dev C++ 5.11环境下运行的结果都是

但是按照标准来分析该表达式,它仍然存在未定义行为。分析如下:

++j+i+++j等价于(++j)+(i++)+j。

在执行第7行时,整型变量i和j的值分别是1和2。当计算表达式++j+i+++j时,需要计算++j和i++,而这两个子表达式的副作用是修改i和j的值。

假设:

1.把计算子表达式++j的值记为_{V++j},它的副作用是将该值写回j,记为_{S++j}

2.将计算子表达式i++的值记为_{Vi++},副作用记为_{Si++}

3.第一个加运算。将获取+运算符的左操作数记为OPL1,右操作数记为OPR1,将左右操作数进行加操作的值记为_{V+1}

4.第二个加运算。将获取+运算符的左操作数记为OPL2,右操作数记为OPR2,将左右操作数进行加操作的值记为_{V+2}

按照运算符的优先级和结合性,这些事件发生的顺序可能是:

_{V++j}→OPL1_{S++j}→OPR1_{Vi++}_{Si++}_{V+1}→OPL2→OPR2_{V+2}

OPL1=3,_{S++j}=>j=3,OPR1=1, _{Si++}=>i=2, _{V+1}=4, OPL2=_{V+1}=4, OPR2=j=3,_{V+2}=7,

 所以,表达式++j+i+++j的值为7. 

也可能按这样的顺序执行:

_{V++j}→OPL1→OPR1→_{Vi++}_{V+1}→OPL2→OPR2_{V+2}_{S++j}_{Si++};

OPL1=3,OPR1=1, _{V+1}=4, OPL2=_{V+1}=4, OPR2=j=2,_{V+2}=6,_{S++j}=>j=3,_{Si++}=>i=2, 所以,表达式++j+i+++j的值为6。   

通过上面的分析,可以肯定地说,这个表达式存在未定义行为。虽然这个表达式在VC++6.0和Dev C++ 5.11环境下运行结果相同,但仍不能说它是正确的表达式。

你可能感兴趣的:(编程语言,蓝桥杯)