简体   繁体   English

C中的序列点和副作用

[英]Sequence points and side effects in C

In this C-FAQ it is give about sequence point ; 在这个C-FAQ中给出了序列点 ;

The Standard states that; 标准规定:
Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. 在前一个和下一个序列点之间,对象的存储值最多只能通过表达式的计算修改一次。 Furthermore, the prior value shall be accessed only to determine the value to be stored. 此外,只能访问先前值以确定要存储的值。

In the examples 在例子中

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

it is clear from first sentence of the statement that these examples are results in undefined behavior . 从声明的第一句可以清楚地看出,这些例子是未定义行为的结果。
In explaining second sentence of the statement it is said that; 在解释声明的第二句时,据说;

second sentence says: if an object is written to within a full expression, any and all accesses to it within the same expression must be directly involved in the computation of the value to be written. 第二句话说: 如果一个对象被写入一个完整的表达式,那么同一个表达式中对它的任何和所有访问都必须直接参与计算要写入的值。 This rule effectively constrains legal expressions to those in which the accesses demonstrably precede the modification. 此规则有效地将法律表达式约束为在修改之前明显存在访问的表达式。 For example, the old standby 例如,旧备用

 i = i + 1 

is allowed, because the access of i is used to determine i's final value. 是允许的,因为i的访问用于确定i的最终值。 The example 这个例子

a[i] = i++

is disallowed because one of the accesses of i (the one in a[i]) has nothing to do with the value which ends up being stored in i (which happens over in i++), and so there's no good way to define. 是不允许的,因为i的一个访问(a [i]中的一个)与最终存储在i中的值无关(在i ++中发生),因此没有好的方法来定义。

My questions are; 我的问题是;
1.What does it mean by, if an object is written to within a full expression, any and all accesses to it within the same expression must be directly involved in the computation of the value to be written. 1.它是什么意思, 如果一个对象被写入一个完整的表达式,那么在同一个表达式中对它的任何和所有访问必须直接参与计算要写入的值。 ?

2.what does it mean by, The example a[i] = i++ is disallowed because one of the accesses of i (the one in a[i]) has nothing to do with the value which ends up being stored in i (which happens over in i++) 2.它是什么意思,例子a[i] = i++ 被禁止,因为i的一个访问(a [i]中的一个)与最终存储在i中的值无关(其中发生在i ++)
Could someone explain it in some easy way? 有人可以用一些简单的方法解释它吗?

My question are; 我的问题是; 1.What does it mean by, if an object is written to within a full expression, any and all accesses to it within the same expression must be directly involved in the computation of the value to be written.? 1.它是什么意思,如果一个对象被写入一个完整的表达式,那么在同一个表达式中对它的任何和所有访问都必须直接参与到要写入的值的计算中。

With a sub-expression like i++ , i is written to. 使用像i++这样的子表达式, i被写入。 Moreover, assignment is an expression, so in i = 2 , i is written to. 而且,赋值是一个表达式,所以在i = 2i被写入。 It may not be immediately obvious that a = b is an expression, but it is. a = b是表达式可能不是很明显,但确实如此。 This is why you can do things like a = b = c , which is good, and if (a = b) which is less good. 这就是为什么你可以做一些事情,比如a = b = c ,这是好的, if (a = b)哪个不太好。

So what it is saying is that if you write to i , with = , or pre- or post- increment, then any access to i must be as part of the calculation of the new value of i. 那么它是什么要说的是,如果你写信给i ,用= ,或前或后加,然后我的任何访问必须是我的新价值计算的一部分。 However, and this is important, the only thing involved in the calculation of pre and post increment is the value of i at the start of the statement . 然而,这很重要,计算前后增量所涉及的唯一事情是在语句开头的 i的值。

2.what does it mean by, The example a[i] = i++ is disallowed because one of the accesses of i (the one in a[i]) has nothing to do with the value which ends up being stored in i (which happens over in i++) 2.它是什么意思,例子a [i] = i ++被禁止,因为i的一个访问(a [i]中的一个)与最终存储在i中的值无关(其中发生在i ++)

Precisely what it says. 正是它所说的。 When you access i in a[i] it is not part of the calculation of the new value of i that results from i++ . 当访问ia[i]它不是新的值的计算的一部分i导致从i++

Could someone explain it in some easy way? 有人可以用一些简单的方法解释它吗?

Easy way: Don't use pre or post increment in an expression. 简单方法:不要在表达式中使用前置或后置增量。 always use them in statements by themselves. 总是在声明中自己使用它们。 If you really really must, do NOT use the same variable anywhere else in the entire statement . 如果你真的必须,请不要在整个语句中的任何其他位置使用相同的变量。

This explanation is weird and I can't make sense of it. 这种解释很奇怪,我无法理解它。

The true explanation is that the expression i++ has a side-effect (incrementing i ) that can be applied anytime after this particular i has been evaluated. 真正的解释是表达式i++具有副作用(递增i ),可以在评估此特定i之后的任何时间应用。

Since outside of sequence points , the C language doesn't guarantee the evaluation order or the time when post-incrementations are applied (likely for performance reasons), three things can happen in the second example (let's assume i = 5 before the line) : 由于在序列点之外,C语言不保证评估顺序或应用后递增的时间(可能出于性能原因),在第二个示例中可能发生三件事(假设在行之前i = 5 ) :

  • The leftmost i (the one in a[i] ) is evaluated first, to calculate the address of a[i] for storage. 首先评估最左边的ia[i]中的a[i] ),以计算用于存储的[i]的地址。 Then the rightmost i is evaluated, then the post-incrementation is applied: The line is performs a[5] = 5; i=6; 然后评估最右边的i ,然后应用后增量:该行执行a[5] = 5; i=6; a[5] = 5; i=6;
  • The rightmost i is evaluated first, then the leftmost one, and then i the post-incrementation is applied when all is said and done: In this case the effects are identical to the above case. 最右边的i首先计算,则最左边的一个,然后i当所有是说,做了-递增后施加:在这种情况下,效果是相同于上面的情况。
  • The rightmost i is evaluated first, the post-incrementation applied immediately, and then the leftmost i is evaluated to calculate the address of a[i] for storage. 首先评估最右边的i ,立即应用后增量,然后评估最左边的i以计算用于存储的[i]的地址。 This time the effect is a[6] = 5; i=6 这次效果是a[6] = 5; i=6 a[6] = 5; i=6 . a[6] = 5; i=6

The choice of outcome depends not only on the choice of compiler, but on the compiler's setting: Microsoft Visual C++ can give different outcomes depending on whether you compile in Debug or Release. 结果的选择不仅取决于编译器的选择,还取决于编译器的设置:Microsoft Visual C ++可以根据您是在Debug还是Release中编译来提供不同的结果。

Finally I got an explanation on SO about this point . 最后我得到了关于这一点的SO的解释 After reading it and FAQ I concluded that; 看完后常见问题 我得出的结论是;

1.The last sentence 最后一句话

Furthermore, the prior value shall be accessed only to determine the value to be stored 此外,只能访问先前值以确定要存储的值

would be like this; 会是这样的;

Furthermore, the prior value of an object shall be accessed only to determine the modified/new value( of same object ) to be stored. 此外,只能访问对象的先前值以确定要存储的( 同一对象的修改/新值。

As it is clear by the example 通过这个例子很清楚

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

in case of expression i = i + 1 prior value (which is 1 here) of i (in RHS) is accessed to determine the value of i to be stored and this is what the statement 在表达式i = i + 1情况下, i (在RHS中)的先前值(在此为1 )被访问以确定要存储的i的值,这就是语句

if an object is written to within a full expression, any and all accesses to it within the same expression must be directly involved in the computation of the value to be written . 如果一个对象被写入一个完整的表达式,那么在同一个表达式中对它的任何和所有访问都必须直接参与计算要写入的值。

says. 说。
While in case of j = i + 1 and a[i] = i , the accessed value of i is just value not prior value as no where i is modified in these statements. 而在的情况下, j = i + 1a[i] = i ,的访问值i 只是重视 不是 现有值作为没有在那里i在这些语句修改。

2.The second question can be explained as; 第二个问题可以解释为;
In case of expression a[i] = i++ or a[i++] = i , first sentence of above statement 在表达式a[i] = i++a[i++] = i ,上述语句的第一句

Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. 在前一个和下一个序列点之间,对象的存储值最多只能通过表达式的计算修改一次。

get failed as i is modified only once between two consecutive sequence point . 失败,因为i 在两个连续的序列点之间只修改了一次 And that's why we need second sentence. 这就是为什么我们需要第二句话。
Both of these examples are disallowed in C because the prior value of i accessed two times ie, i++ itself access prior value of i in the expression to modify it and hence other access of prior value / value of i is needless as it is not accessed to determine the modified value to be stored. 这两个例子是使用C不允许的,因为在现有值i访问两次,即, i++本身的访问之前值 i在表达式对其进行修改和先前值的因而其它接入/ i是不必要,因为它不访问确定要存储的修改值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM