++i和i++关于[自增运算符]和[顺序点]

1 篇文章 0 订阅
1 篇文章 0 订阅
  又是招聘季,同学有去找工作的,谈到i = 1, a = i++ + i++ + ++i的值是多少的问题
  这里一个语句中出现多次++操作,各个子表达式的值到底该是多少呢?
  这是个老问题,当初上课的时候的想法是,这种边缘代码,根本不值得花时间。


结论:

  今天无聊去求是了一下,结论是上述语句在c标准中是【未定义】的。
  这里要说明一下c标准中的几个概念:
implementation-defined(实现决定):编译器可以按照自己的方便在候选的几种选择中选择一种方案实现,必须文档说明。
unspecified(未说明):undocumented implementation-defined:同实现决定,可以不在文档注明。
undefined(未定义):标准不对编译器的行为做规定。(当然,最好当然是直接不通过编译,有的编译器会按自己的方式实现)


  具体各标准的版本区别我就懒得去扒了,基本上是c99和c++03的标准都是这样。

正题:
  c和c++中有一些表达式会产生side effect,就是除了表达式本身,还会改变其他内存或文件的内容(可能不太准确,姑且这样理解吧)
++操作符就是其中之一。
  一个sequence point(顺序点)就是上一次求值所产生的side effect已经生效,下一次求值产生side effect还未开始。
  标准中有这么一条( Clause 6.5#2 of the C99 specification):
两个相邻的顺序点之间,同一个内存单元的值只能改变一次。如果一个值被改变,此期间对该值的引用只能用于改变该值(读在写之前)。

  文首那个表达式就是改变了两次,违反了第一句话,c+和c++标准作为未定义处理。

  第二句话的反例是

           a[i] = i++;

  这里i被改变,而i同时被读取来作为数组a的下标,不是用来改变i,所以也是未定义。

  所以这个表达式的问题不仅在于“结果看编译器”,而是更严重的“未定义”,编译器编译出会崩溃的代码都是可能的。

  如果这个表达式在每个“+”处存在顺序点,那答案就很确定: 1+2+4。
  可惜的是c和c++仅在有限的几种情况下默认存在顺序点:(详见文末wiki链接)
1、 && (logical AND), || (logical OR), comma operators
2、三元操作符? : 的“?”处
3、full expression完整表达式结束处。完整表达式:不是另一个表达式的字表达式(for中的3个表达式也算完整表达式)。一般的语句都属此情况,分号处都存在顺序点。
4、将要进入函数调用前。即所有参数求值完毕,还未调用函数。(函数参数的求值和压栈顺序本身是实现决定的,见上文)。也就是说f(i++)+g(i++)+f(++i)是well-defined的,因为中间存在顺序点。
5、函数返回,返回值拷贝到调用上下文。(仅c++,wiki如是说,我就懒得考证了。。)
6、定义变量处。如int a = 5;(感觉这和3有重复)
7、定义多个变量时,多个变量间。如int a=5,b=3; (此逗号处也有顺序点,注:wiki中给了c++标准的引用,c未考证)

对于顺序点的理解:
  如果我们认为程序都跑在多核机器上,且在任何可能的地方都被并行化,顺序点就可以看作一个分隔标记,以保证逻辑的正确性,每个顺序点之前的语句都要比它之后的语句先执行,两个顺序点中间的指令的顺序不做规定。(刚好和数据库中无序事务的情形相反:事务中的顺序指定,事务间不做要求)
  这样,标准里的那两句话就很好理解了:
两个相邻的顺序点之间(暂叫无序段。。),同一个内存单元的值只能改变一次。
——若能改变多次,2次改变被分配到不同的核执行,因为无序段中的指令顺序不做规定,可能引起不一致(写写)的情况。
如果一个值被改变,此期间对该值的引用只能用于改变该值(读在写之前)。
——同样,这里会出现读写不一致。


总之,这两句话可以看作保证并发情况下逻辑正确性的一种简单约束,当然这种底层地方做复杂的约束时间开销上可能会得不偿失。(另一种意图是交给编译器一定的自由,方便某些设计和做优化)

不过就顺序点的机制看,c语言很难做到指令级并行,因为对c的情形来说,这种顺序点的定义太密集,太僵硬。
要做方便的并行程序设计,还是需要专门的语言。

参考:http://en.wikipedia.org/wiki/Sequence_point
http://c-faq.com/expr/seqpoints.html
http://c-faq.com/expr/evalorder4.html
http://en.wikipedia.org/wiki/Undefined_behavior

找工作离我好遥远。。TT
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值