我无法理解C99中的一些句子

时间:2013-09-26 16:12:02

标签: c c99 language-lawyer

在C99 6.5中说:

  

在前一个和下一个序列点之间,一个对象应该具有它   通过表达式的评估,最多修改一次存储值。   此外,先前的值应只读以确定该值   存储

什么是“此外,先前的值只能读取以确定要存储的值”是什么意思?在C99中,为什么a[i++] = 1是未定义的行为?

2 个答案:

答案 0 :(得分:8)

定义了

a[i++] = 1(除非其他原因未定义,而不是副作用的排序:超出限制的访问权限,或未初始化的i)。

你的意思是a[i++] = i,这是未定义的行为,因为它在与i相同的序列点之间读取i++,这会改变它。

“此外,先前值应只读以确定要存储的值”部分表示允许i = i + 1;,但它从i读取并修改i

另一方面,a[i] = (i=1);是不允许的,因为尽管只向i写了一次,但i的读取并非用于计算存储的值。

答案 1 :(得分:8)

“先前的值应该是只读的,以确定要存储的值”。措辞无疑是违反直觉的;为什么要读取值的目的

该句的要点是强制要求依赖哪些操作。

我会从Pascal's answer窃取示例。

此:

i = i + 1;

非常好。 i在同一个表达式中被读取和写入,没有中间序列点,但是没关系,因为在读取完成之后才能进行写入。在完全评估表达式i + 1及其子表达式i之前,无法计算要存储的值。 (并且i + 1没有可能在写入之后延迟的副作用。)该依赖性强制执行严格排序:必须在写入开始之前完成读取。

另一方面,这个:

a[i] = (i=1);

有未定义的行为。子表达式a[i] 读取 i的值,子表达式i=1 写入 i的值。但是写入存储在i中的值不依赖于左侧读取i的评估,因此未定义读取和写入的顺序。 “要存储的值”是1; ia[i]的读取并未确定该值。

我怀疑这种混淆是为什么2011年修订的ISO C标准(草案形式为N1570)重新措辞了该部分。该标准仍然具有序列点的概念,但6.5p2现在说:

  

如果标量对象的副作用相对于其中任何一个都没有排序   对同一个标量对象或值有不同的副作用   使用相同标量对象的值进行计算,行为是   未定义。如果有多个允许的排序   表达式的子表达式,如果这样的话,行为是不确定的   任何顺序都会出现无序的副作用。

第1段明确说明了C99中隐含的假设:

  

对运算符的操作数的值计算进行排序   在运算符结果的值计算之前。

第5.1.2.3节第2段解释了在之前排序的之后的排序。