7

在这个C-FAQ中给出了关于序列点的信息;

该标准规定;
在前一个和下一个序列点之间,对象的存储值最多只能通过表达式的评估修改一次。此外,只能访问先验值以确定要存储的值。

在示例中

i = i++;
a[i] = i++;

从声明的第一句话可以清楚地看出,这些示例是导致未定义行为的结果。
在解释该声明的第二句话时,据说;

第二句话说:如果在一个完整的表达式中写入一个对象,那么在同一个表达式中对它的任何和所有访问都必须直接参与到要写入的值的计算中。该规则有效地将合法表达限​​制为那些访问明显先于修改的表达。例如,旧的备用

 i = i + 1 

是允许的,因为 i 的访问用于确定 i 的最终值。这个例子

a[i] = i++

是不允许的,因为 i 的访问之一(a[i] 中的那个)与最终存储在 i 中的值无关(这在 i++ 中发生),因此没有好的方法来定义。

我的问题是;
1.这是什么意思,如果在一个完整的表达式中写入一个对象,那么在同一个表达式中对它的任何和所有访问都必须直接参与到要写入的值的计算中。?

2.这是什么意思,该示例a[i] = i++ 是不允许的,因为 i 的访问之一(a[i] 中的那个)与最终存储在 i 中的值无关(这在 i++ 中发生)
可以有人以某种简单的方式解释它吗?

4

3 回答 3

6

我的问题是;1.这是什么意思,如果在一个完整的表达式中写入一个对象,那么在同一个表达式中对它的任何和所有访问都必须直接参与到要写入的值的计算中。?

i++使用像,这样的子表达式i被写入。此外,赋值是一个表达式,因此 ini = 2i写入。这a = b是一个表达式可能不是很明显,但它确实是。这就是为什么你可以做这样的事情a = b = c,哪个好,if (a = b)哪个不太好。

因此,它的意思是,如果您写入i、with=或 pre-或 post-increment,那么对 i 的任何访问都必须作为 i 的新值计算的一部分。但是,这很重要,计算前后增量的唯一内容是i 语句开头的值。

2.这是什么意思,示例 a[i] = i++ 是不允许的,因为 i 的访问之一(a[i] 中的那个)与最终存储在 i 中的值无关(其中在 i++ 中发生)

正是它所说的。当您访问它时ia[i]它不是计算新值的一部分i,结果来自i++.

有人可以用一些简单的方式解释它吗?

简单的方法:不要在表达式中使用前置或后置增量。总是在自己的语句中使用它们。如果您真的必须这样做,请不要在整个语句的其他任何地方使用相同的变量。

于 2013-07-04T16:41:58.650 回答
2

这个解释很奇怪,我无法理解。

真正的解释是该表达式i++具有副作用(递增i),可以在i评估此特定内容后的任何时间应用。

由于在序列点之外,C 语言不保证评估顺序或应用后增量的时间(可能出于性能原因),在第二个示例中可能会发生三件事(假设i = 5在行之前):

  • 首先评估最左边i的(在 中的那个a[i]),以计算 a[i] 的地址以进行存储。i然后评估最右边的,然后应用后增量:执行该行a[5] = 5; i=6;
  • 首先计算最右边i的,然后是最左边的,然后i在一切就绪后应用后增量:在这种情况下,效果与上述情况相同。
  • 首先计算最右边i的,立即应用后增量,然后计算最左边i的以计算 a[i] 的地址用于存储。这次的效果是a[6] = 5; i=6

结果的选择不仅取决于编译器的选择,还取决于编译器的设置:Microsoft Visual C++ 可以根据您是在 Debug 还是在 Release 中编译给出不同的结果。

于 2013-07-04T15:27:04.993 回答
1

最后我得到了关于这一点的解释。在阅读了它和常见问题解答后, 我得出结论

1.最后一句话

此外,只能访问先验值以确定要存储的值

会是这样的;

此外,仅应访问对象的先前值以确定要存储的(同一对象的)修改/新值 。

正如示例所清楚的那样

 int i = 1, j, a[5];    
 i = i + 1;
 j = i + 1;
 a[i] = i; 

在表达式的情况下,访问(在 RHS 中)的i = i + 1先验值(在1此处)i以确定i要存储的值,这就是语句的内容

如果在完整表达式中写入对象,则在同一表达式中对其的任何和所有访问都必须直接参与要写入的值的计算。

说。
而在 and 的情况下j = i + 1a[i] = i访问的值 i 只是 而不是 先前值,因为i 在这些语句中没有修改 where。

2.第二个问题可以解释为;
在表达式a[i] = i++or的情况下a[i++] = i,上述语句的第一句

在前一个和下一个序列点之间,对象的存储值最多只能通过表达式的评估修改一次。

get failed因为 在两个连续的序列点之间i修改一次。这就是为什么我们需要第二句话。
这两个示例在 C 中都是不允许的,因为 i 访问了两次的先验值,即,i++ 它本身访问表达式中 的先验值i 来修改它,因此不需要其他访问先验值 /的值, i 因为它没有被访问以确定修改的要存储的值。

于 2013-07-13T10:42:52.470 回答