I have the following code
int m[4]={1,2,3,4}, *y;
y=m;
*y = f(y++); // Expression A
My friend told me that Expression A
has a well defined behavior but I am not sure whether he is correct.
According to him function f()
introduces a sequence point
in between and hence the behavior is well defined.
Someone please clarify.
P.S: I know we should not write such code for practical purpose. It is just for the purpose of learning. :)
At best, the code in question has unspecified behavior. For the assignment operators, "the order of evaluation of the operands is unspecified" (C99 §6.5.16/4).
If the left operand is evaluated first, the result of f(y++)
will be stored in m[0]
. If the right operand is evaluated first, the result will be stored in m[1]
.
As for whether the behavior is undefined, the relevant paragraph is:
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 read only to determine the value to be stored (C99 §6.5/2).
If the left side is evaluated first, then we run afoul of the second sentence because the ordering is:
y
is read on the left side to dereference ity
is read on the right side to increment ity++
is complete and y
is written to)In step 1, the "prior value" of y
is read but for a purpose other than "determining the value to be stored." Thus, the behavior is indeed undefined because one valid evaluation order yields undefined behavior.
You are absolutely right about function call introducing a sequence point. However, that sequence point does not save the situation in your case.
Consider this simple example first
i = some_function(i++);
Is it valid? Yes, it is. Why? It is valid because the sequence point introduced by the function (the one you are talking about) separates two modifications of i
from each other, thus making the code valid. There's no order of evaluation of this expression that would result in i
being modified twice without an intervening sequence point.
However, let's return to your variant
*y = f(y++);
In this case that sequence point exists as well. However, the language makes no guarantee about the order of evaluation of =
operator (meaning: the language makes no guarantee about which operand of assignment operator is evaluated first: left or right). It is quite allowable for the compiler to evaluate the left-hand side first (*y
), the function argument second (y++
), then call the function and then perform the actual assignment. In this potential scenario the first two steps - reading the y
and modifying the y
- are not separated by a sequence point. Thus, the behavior is undefined.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With