Q如果我不想学习那些复杂的规则,有什么办法可以避免这些未定义求值顺序的困难?
A最简单的答案是,如果你避开那些没有相当明显解释的表达式,那么在大多数情况下,你也会避开那些未定义的表达式。(当然,“相当明显”对不同的人来说意味着不同的东西。这个答案只有在你同意以下表达式a[i] = i++和i = i++不是“相当明显”的情况下才有效。)
为了更精确一些,这里有一些更简单的规则,虽然比标准中的规则稍微保守一些,但它们能帮助确保你的代码“相当明显”,并且对编译器*和*你的其他程序员来说同样容易理解。
i = i + 1因为尽管对象i出现了两次并且被修改了,但获取i旧值的出现(在等号右侧)被用来计算i的新值。
c = *p++在规则下是被允许的,因为被修改的两个对象(c和和p
*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或者两个*不同的*数组索引i和j时。
(c = getchar()) != EOF && c != '\n'(在读取一行时,在while循环中常见)是合法的,因为变量c的第二次访问发生在&&所暗示的顺序点之后。(如果没有顺序点,该表达式将是非法的,因为访问c在将其与右侧的'\n'进行比较时,并没有“确定要存储的值”。)