开发者

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 beha开发者_C百科vior 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:

  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.


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.


The expression is not well defined:

A valid interpretation of the expression is:

(1) int* t0 = y++; 
(2) int  t1 = f(t0);
(3) int& t2 = *y;
-----------------
t2 = t1; 

An equally valid interpretation of the expression is:

(1) int& t2 = *y;
(2) int* t0 = y++; 
(3) int  t1 = f(t0);
-----------------
t2 = t1; 

Both of these are vaalid and generate different results. So the expression has undefined result.


EDIT: this is incorrect, however I'm leaving it here because the discussion that follows in the comments is somewhat illuminating, and I hope valuable.

It's well-defined based on the evaluation order of operators in C (or C++).

Assignment forces evaluation of the right hand side of the expression first. Function application forces evaluation of its arguments first, so the effect seems reasonably clear (although I haven't tried running it, so feel free to correct me!). We can rewrite this using temporary variables (I'll call them t0 and t1), and I believe this might be a little clearer:

t0 = y++;
t1 = f(t0);
*y = t1;

The term "sequence point" is a bit of a red herring. A sequence point isn't really created, rather it's just the consequence of having a strict evaluation order defined for the language.

EDIT: While this answer seems intellectually satisfying, James McNellis's answer quotes the relevant piece of the C99 spec that states that the evaluation order of assignment is not well-defined. Full credit to him for actually checking his facts. I'm going to revise my answer from "it's well-defined" to "it's probably well-defined with respect to a particular compiler", as I think it's unlikely that most compilers would regularly change the order in which they emit such code (I say "probably" to account for any very aggressive optimisation).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜