在http://blog.chinaunix.net/u/8681/showart.php?id=2257718
一文中我已经花过一些时间了解副作用与序列点的问题, 但是, 境过时迁, 我发现我对此文中引用的标准的一些部分并未吃透.
如下
int a = 3, b = a;
这样的语法是遵循标准的吗, 用实际的编译器来验证的话, VC2008, GCC 4.2.3, pc-lint 9 全都OK.
但我隐隐怀疑声明语法之后才是一个序列点, b = a时读取了a的值, 而a=3 对a进行了赋值, 一读一写却非同时. 这对应了标准中说的:
...or is modified and the prior value is read other than to determine the value to be stored (6.5)
Annex C中列出的序列点有一种是:
--- The end of a full expression: an initializer (6.7.8);
an initializer(6.7.8) 是full expression之一, 就是上述的
= 3 的部分, 为了严格遵循标准中对initializer的定义, 前面没写a.
这个3之后的逗号处, 也是一个序列点, 这一点解释了为什么这样的写法是被主流编译器普遍接受的.
6.7.8 给出的initializer的定义, 也保证了这一点, 另外,
<
> page 1380 又重复列出了这一情况, 并且显式地说是
object declaration initializer
但是
a = a + 1 ;
呢, 显然从直觉上这个写法一定没有问题, 因为它等价于a++, 但这个表达式中, 第一个a是被赋值被修改的, 而第2个a被读取, 两处!
我在下面的网页上读到:
> Furthermore, the prior value shall be
> accessed only to determine the value to be stored.The requirements of
> this paragraph shall be met for each allowable ordering of the
> subexpressions of a full expression; otherwise the behavior is
> undefined."
This one is much more difficult. If you read the current value of an
object, and then write to that same object, without an intervening
sequence point, then you can't read the value for any purpose other
than determining the value that is to be written.
Again, as a practical matter that's because the absences of a sequence
point allows the read and the write to be in any order, and it even
allows them to interfere with each other. It's allowed only if it's
inherently impossible to know what value to write, until you've
finished reading the value; that guarantees that the read and the write
have to be in the right order, and can't interfere with each other,
even in the absence of a sequence point.
只在这种情况下是允许的: 如果不先完成读操作的话, 本质上就不可能知道怎么写, 这样的逻辑保证了读和写一定是以正确的顺序发生的, 上例中, 赋值不可能发生在读取 a的操作之前, 所以没有歧义.
int i = a + a++; 就不同了. 无法保证第一个a和第二个a++表达式的evaluation顺序, 注意不是优先级和结合性了.
阅读(937) | 评论(0) | 转发(0) |