sequence point

顺序点,C语言冰山位于海面下的角落。
副作用side effect,简单理解就是变量值被改变这个事实。i++这个表达式,副作用就是i被增加1。a = 10;这个表达式,副作用就是a被赋值成10。
一个复杂的表达式,其求值过程是有迹可循的。例如:i++ + ++i 这个表达式,根据运算符的结合性或优先级关系,可以被人为是如下等效形式:(i++) + (++i).现在的问题来了,它的求值结果是什么?答案是:未定义行为(undefined)。未定义的意思是:无法预测结果。对比另一个叫做为未指定行为(unspecified) ,说的是有几个结果,发生哪一个不知道。显然,未定义是更危险的。
这里面涉及到顺序点这个事。具体细节参考sequence point « Eternity

简单的说,就是在顺序点之前,何时完成副作用,是不确定的事,不能根据子表达式,就说在此子表达式完成副作用。

顺序点是语法解析过程,对指定的几个词法位置的特殊标记。就好比道路上的路牌作用。
常用的顺序点(我用@符号表示这个路牌):
1)  分号位置。
  a = 10 ;@ 
2)  逗号表达式位置
  a = 10 ,@  i++ ,@ a=i ;@
3)  三目运算符
  a>0 ?@ i++ :@ j++ ;@
4)  ......

副作用被限制在顺序点之间的任意位置发生。即两个@路牌之间发生。
回到 (i++) + (++i)这个面试和考试常考的地方,因为+号不是顺序点,所以,不能断言出i++的副作用在+之前完成。

可以想象成i++和++i的副作用是多线程方式(parallel)方式进行的。这是个多线程写。
另一个例子是a[i] = i++;因为[]和=都不是合规的顺序点,因此将发生多线程的读写。因此上述两个例子的结果都是不确定的。

实际上没有多线程,只是想象,帮助你理解为什么不能那么写程序,也不能拿这种例子考试别人。
只是编译器厂家可以做生成的指令重排列做效率优化(只要保证在顺序点之前实现副作用)。重排列指令顺序后,等效于多线程(单核)指令交替执行的效果。

下面是各个编译器上机实验:

#include <iostream>
int main()
{   
    int i = 1; 
    int a = i++ + ++i;
    std::cout << a << std::endl;
    return 0;
}

GCC: 提示 undefined behavior。不是说未定义变量i。

 CLANG:提示的更清楚,多个写操作发生了。

 VS2005:未提示
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值