Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Behavior of an expression: Defined or Undefined?

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

like image 737
Prasoon Saurav Avatar asked Jul 24 '10 16:07

Prasoon Saurav


2 Answers

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:

  1. The value of y is read on the left side to dereference it
  2. The value of y is read on the right side to increment it
  3. There is a sequence point after the evaluation of the arguments to the function (so, the side effect of y++ 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.

like image 90
James McNellis Avatar answered Oct 03 '22 20:10

James McNellis


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.

like image 42
AnT Avatar answered Oct 03 '22 20:10

AnT