- 论坛徽章:
- 2
|
j+++i这个表达式的,根据C标准 "the behavior is undefined"
也就是说这是个错误的程序,编译器给出任何结果都可以。
原因是:一个对象在两个顺序点(sequence point)之间只能读写一次。
j++产生一次写j,同时j+++i又有一次读j(并且读出的数据并不是用来改变j的值)这违反了C表达式的限制。
delimy 发表于 2010-10-01 17:04
确实跟标准说的不一致呀。
标准里的第一句话说,sequence point之间对象的值只能改变一次;第二句话说,对象被改变之前的值只能在“决定对象的终值”时引用。
标准里并没有说sequence point之间只能读写一次。
比如两个sequence point 之间读了一次 i 写了一次 i ,这个表达式肯定没事呀。。。。。。。
标准里说的第二句说非常不好理解,
Furthermore, the prior value shall be accessed only to determine the value to be stored.
根据http://c-faq.com/expr/seqpoints.html上面的解释:
And that's what the second sentence says: if an object is written to within a full expression, any and all accesses to it within the same expression must be directly involved in the computation of the value to be written
如果对象在full expression中会被改动(写入),则这个full expression中所有对该对象的引用一定是为了“确定这个对象的最终值”。 i = i +1 就是这种情况,i 会被写入, i + 1 里面引用 i 是为了确定 i 的最终值。 a[ i ] = i ++ 就违反了这条规则(虽然没有违反第一条),a [ i ] 中对 i 的引用不是为了“确定i的终值”。
我觉得还是标准里没说清楚,“the prior value”意思显然是“对象被改动之前的值”,但我怎么知道引用的是“对象被改动之前的值”还是“对象被改动之后的值”呢?
按照标准的意思,a[ i ] 里引用的就是 i 的“the prior value”。那 i ++ + j 里有没有引用“the prior value”呢? ++i + j 有没有引用“the prior value”呢?( a = 1) + a 里有没有引用“the prior value”呢? *p++ = 0里有没有引用“the prior value”呢?a = b = 4有没有引用“the prior value”呢?
最终还是要看“the prior value”是怎么定义的。
在C语言的设计之初,并没有严格定义求值过程,像前置++、后置++这种东西只是抽象地规定“在操作之前加一”还是“在操作之后加一”,但何为“操作”呢?
规范则严谨地定义求值过程,引入sequence point的概念后就可以保证,++肯定会在下一个sequence point前生效,至于在什么时候生效则不能确定。像 a = i ++ 按C语言最初的语义,应该是可以根据优先级来确定求值行为的,自增在赋值之后发生。标准里却认定其为“未定义”行为。如果是a[k] = i ++情况又是怎么样呢?*p++ = 0 , c [ i ++ ] = 0这种经典语句是不是“未定义”呢?它们有没有引用了“the prior value“呢?结果又绕回什么是“the prior value”的问题上来了。不过这两种情况下,按照原始C语义里的优先级来解释,显然是引用的“the prior value”,那么根据标准,它们全是未定义的。
我觉得,第一条肯定不能违反,第二条还有商量的余地。规范里的第二条基本上把++,--操作符给废掉了。像 c [ i ++ ] = 0这样的表达式,虽然是未定义行为(如果理解正确的话),编译器显然可以确定会发生什么事。 i++ + j 亦是同理。这能不能看作约定俗成的规则呢? 全世界写编译器的人大概都不会因为这种”未定义“行为而中止编译过程吧,他们对”该发生什么事“的认识也应该是统一的吧。
===================================
PS:在CU上搜到这个帖子,http://bbs.chinaunix.net/viewthread.php?tid=310576,六年前就有人解释地这么清楚了。。。。。。 |
|