Using a content pointer when designating a pointer

I always understood that the lack of a sequence point after reading the correct expression in the assignment makes an example similar to the following undefined result:

void f(void) { int *p; /*...*/ p = (int [2]){*p}; /*...*/ } // p is assigned the address of the first element of an array of two ints, the // first having the value previously pointed to by p and the second, zero. The // expressions in this compound literal need not be constant. The unnamed object // has automatic storage duration. 

However, this is Example 2 in the section "6.5.2.5. Mixed Literals" in the draft committee for the C11 standard, the version designated as n1570, which, as I understand it, is the final draft (I do not have access to the final version).

So my question is: is there anything in the standard that gives this specific and specific behavior?

EDIT

I would like to elaborate on what I see as a problem, in response to some of the discussions that have arisen.

We have two conditions under which an undefined assignment is explicitly specified, according to 6.5p2 of the standard specified in dbush's answer:

1) The side effect of a scalar object is independent of the other side of the effect on the same scalar object.

2) A side effect on a scalar object is independent of the value of the calculation using the value of the same scalar object.

An example of element 1 is "i = ++ i + 1". In this case, the side effect of writing the value i + 1 to i due to ++ i does not affect the side effect of assigning RHS to LHS. There is a point in the sequence between calculating the values ​​of each side and the RHS assignment for the LHS, as described in 6.5.16.1 given in Jens Gustedt's answer below. However, the change i due to ++ i am not subject to this point of the sequence, otherwise the behavior to be determined.

In the above example, we have a similar situation. There is a calculation of values, which includes creating an array and converting this array into a pointer to its first element. There is also a side effect of writing a value for part of this array, * p for the first element.

So, I don’t see what we have in the standard that modifying the other uninitialized first element of the array will be sequenced before writing the address of the array to p. As for this modification (writing * p on the first element) is different from the modification of writing i + 1 to i?

In other words, suppose that the implementation considered the representation of interest in the example as three tasks: 1st, allocate space for the composite literal; 2nd: assign a pointer to the specified space on p; 3rd: write * p to the first element in the newly allocated space. The calculation of the values ​​for RHS and LHS will be sequenced before the assignment, since the calculation of the RHS value requires only an address. How does this hypothetical implementation fall short of the standard?

+5
source share
3 answers

In (int [2]){*p} , *p provides the initial value for a composite literal. This is not a task, and it is not a side effect. The initial value is part of the object when creating the object. There is no moment when the array exists and it is not initialized.

At p = (int [2]){*p} we know that the side effect of updating p sequenced after calculating the right side, because C 2011 [N1570] 6.5.16 3 says: "The side effect of updating the stored value on the left of the operand is ordered after calculating the values ​​of the left and right operands.

+1
source

You need to look at the definition of an assignment operator in 6.5.16.1

A side effect of updating the stored value of the left operand is to order after calculating the values ​​of the left and right operands. Operand scores are unaffected.

So, here you clearly see that he first evaluates the expressions on both sides in any order or even at the same time, and then saves the value of the right in the object indicated on the left.

In addition, you should be aware that LHS and RHS assignments are priced differently. The quotes are too long, so here is the summary

  • For LHS, evaluation leaves “lvalues,” that is, objects like p are untouched. In particular, it does not examine the contents of an object.

  • For RHS, there is a “lvalue conversion”, that is, for any object found there (for example, *p ) the contents of this object.

  • If RHS contains an array type lvalue, this array is converted to a pointer to its first element. This is what happens to your complex literal.

Edit: You added another question

How about this modification (writing * p on the first element) different from modifying the record i + 1 to i?

The difference is simply that i in the LHS assignment and therefore needs to be updated. An array from a composite literal is not in LHS and therefore does not need to be updated.

+6
source

Section 6.5p2 of the C standard indicates why this is true:

If the side effect of the scalar object is independent of another side effect on the same scalar object or the value of the calculation using the value of the same scalar object, the behavior is undefined. If there are several valid orders of expression subexpression, the behavior is undefined if such an Inconsistent side effect occurs in any of the orders. 84)

Footnote 84 states:

84) This paragraph displays undefined expression expressions such as

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

letting

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

The published snippet from 6.5.2.5 falls under the latter, since there is no side effect.

+4
source

Source: https://habr.com/ru/post/1275327/


All Articles