sequence point

sequence point,第1张

顺序点,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 
int main()
{   
    int i = 1; 
    int a = i++ + ++i;
    std::cout << a << std::endl;
    return 0;
}

GCC: 提示 undefined behavior。


不是说未定义变量i。


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



 VS2005:未提示
 

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/634432.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-16
下一篇 2022-04-16

发表评论

登录后才能评论

评论列表(0条)

保存