7

In this C-FAQ it is give about sequence point;

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. 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.

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.?

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++)
Could someone explain it in some easy way?

haccks
  • 104,019
  • 25
  • 176
  • 264

3 Answers3

6

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.?

With a sub-expression like i++, i is written to. Moreover, assignment is an expression, so in i = 2, i is written to. It may not be immediately obvious that a = b is an expression, but it is. This is why you can do things like a = b = c, which is good, and if (a = b) which is less good.

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. 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.

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++)

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++.

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.

Tom Tanner
  • 9,244
  • 3
  • 33
  • 61
2

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.

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) :

  • The leftmost i (the one in a[i]) is evaluated first, to calculate the address of a[i] for storage. Then the rightmost i is evaluated, then the post-incrementation is applied: The line is performs 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.
  • 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. This time the effect is 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.

Medinoc
  • 6,577
  • 20
  • 42
  • Your explanation is about UB of `a[i] = i++` and you explained it well but I need explanation for my questions. – haccks Jul 04 '13 at 15:46
  • Alas, I don't see an explanation for the parts you quoted. They seem nonsensical to me. – Medinoc Jul 04 '13 at 16:00
  • Yes, it is also nonsensical to me and that's why I asked this question. – haccks Jul 04 '13 at 16:02
  • 4
    Your explanation makes it sound like there is a small number of possible orderings and one of these will happen. This would correspond to the concept of **unspecified behavior** in the standard. What the standard says is that `a[i] = i++;` is **undefined behavior** (6.5:2 in C99), so your explanation, however “true” it seems to you, is not equivalent to the standard. – Pascal Cuoq Jul 04 '13 at 16:03
  • In the context of this one example, there are only so many permutations of A, B and C when C can't occur before B... In the context of such a computation, it's more "either-or" undefined and not "nasal demons" undefined... – Medinoc Jul 04 '13 at 16:33
  • 2
    @Medinoc There is a name for “either-or undefined”. That name is “unspecified”. In the context of this one example, the standard deliberately avoids using this name, using “undefined behavior” instead. This allows the compiler to make demons fly out of your nose if you compile or execute this program. – Pascal Cuoq Jul 04 '13 at 17:21
  • 3
    @Medinoc: To follow on from Pascal's comment, the compiler is allowed to assume that you don't write code that invokes UB, and thus to make optimisations (etc.) accordingly. If you *do* write such code, then the assumption is invalid, and the resulting behaviour may be completely unexpected. – Oliver Charlesworth Jul 04 '13 at 17:23
1

Finally I got an explanation on SO about this point . 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 R.H.S) is accessed to determine the value of i to be stored and this is what the statement

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.

2.The second question can be explained as;
In case of expression a[i] = i++ or a[i++] = i, first sentence of above statement

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. 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 i.e, 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.

Community
  • 1
  • 1
haccks
  • 104,019
  • 25
  • 176
  • 264
  • hey @haccks according to your second explanation you assumed that the value we are writing to is 'i' but it is actually a[i]....confusion for me.please show me the path! – OldSchool Mar 24 '14 at 15:39
  • @Bayant_singh; In which line? – haccks Mar 24 '14 at 15:41
  • Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. – OldSchool Mar 24 '14 at 15:43
  • please tell me where could i find complete reference for this – OldSchool Mar 24 '14 at 15:45
  • The expression `i++` is writing to `i`. In `a[i] = i++`, there are two write operation-- One by `++` (to `i`) and one by `=` (to `a[i]`). – haccks Mar 24 '14 at 15:49
  • Yes. But You can see `i++` as `i = i + 1`. In this case you are also writing to `i`. – haccks Mar 24 '14 at 15:51
  • two write operations on different operands can lead to UB?i think it is UB if operations (more than once) on same operand rather than two operands in an expression is done?Friend you have another puzzle for me..;) – OldSchool Mar 24 '14 at 15:54
  • i am confused with the statement "Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression."it is talking about "an object" not the two in same expression – OldSchool Mar 24 '14 at 15:58
  • @Bayant_singh; *two write operations on different operands can lead to UB?*: **No**. Ex- `a[i] = j++` two write operations but it will not invoke UB. – haccks Mar 24 '14 at 16:03
  • @Bayant_singh; Havn't you raed in second explanation 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.` **get failed** in this case. So forget this statement for second explanation. – haccks Mar 24 '14 at 16:07
  • but you written"i is modified only once between two consecutive sequence point." and i am unable to pick the two consecutive sequence points which you are talking about? – OldSchool Mar 24 '14 at 16:22
  • @Bayant_singh; Read this to know about sequence point: http://en.wikipedia.org/wiki/Sequence_point – haccks Mar 24 '14 at 16:26