prev up next   top/contents search

comp.lang.c FAQ 列表· 问题 3.11

Q如果我不想学习那些复杂的规则,有什么办法可以避免这些未定义求值顺序的困难?


A最简单的答案是,如果你避开那些没有相当明显解释的表达式,那么在大多数情况下,你也会避开那些未定义的表达式。(当然,“相当明显”对不同的人来说意味着不同的东西。这个答案只有在你同意以下表达式a[i] = i++i = i++不是“相当明显”的情况下才有效。)

为了更精确一些,这里有一些更简单的规则,虽然比标准中的规则稍微保守一些,但它们能帮助确保你的代码“相当明显”,并且对编译器*和*你的其他程序员来说同样容易理解。

  1. 确保每个表达式最多修改一个对象。这里的“对象”是指一个简单变量,或者一个数组元素,或者指针指向的位置(例如*p)。“修改”是指简单的赋值,使用=运算符,或者复合赋值,使用像+=, -=*=这样的运算符,或者使用++--(无论是前缀还是后缀形式)的增量或减量。
  2. 如果一个对象(如上定义)在表达式中出现一次以上,并且是被修改的对象,那么请确保*所有*获取该对象值的出现都参与了要存储的新值的计算。这条规则允许表达式
    	i = i + 1
    
    因为尽管对象i出现了两次并且被修改了,但获取i旧值的出现(在等号右侧)被用来计算i的新值。
  3. 如果你想打破规则 1,请确保正在修改的几个对象是明确不同的,并尽量将修改限制在两个或最多三个,并且风格要与以下示例相匹配。(另外,请确保你继续遵守规则 2 来处理每个被修改的对象。)表达式
    	c = *p++
    
    在规则下是被允许的,因为被修改的两个对象(cp
    	*p++ = c
    
    )是不同的。表达式*p也是允许的,因为(即它本身和它指向的内容)都被修改了,但几乎可以肯定它们是不同的。同样,两者
    	c = a[i++]
    and
    	a[i++] = c
    
    是被允许的,因为c, i,而a[i]都假定是不同的。最后,像
    	*p++ = *q++
    
    	a[i++] = b[j++]
    
    这样的表达式,其中*三个*事物被修改(第一个表达式中的, q,而*p,第二个表达式中的i, j,而a[i]),是被允许的,*如果*所有三个对象都不同,也就是说,只有当使用两个*不同的*指针q或者两个*不同的*数组索引ij时。
  4. 你也可以打破规则 1 或 2,只要你在两个修改之间,或者在修改和访问之间插入一个定义好的顺序点运算符。表达式
    	(c = getchar()) != EOF && c != '\n'
    
    (在读取一行时,在while循环中常见)是合法的,因为变量c的第二次访问发生在&&所暗示的顺序点之后。(如果没有顺序点,该表达式将是非法的,因为访问c在将其与右侧的'\n'进行比较时,并没有“确定要存储的值”。)


prev up next   contents search
关于此 FAQ 列表   关于 Eskimo   搜索   反馈   版权

Eskimo North 托管