views:

211

answers:

3
void main(void)
{
  int x,y,z;
  x=y=z=1;

  z = x && y && ++z;//is this fine?
}

I have lately started reading about sequence points stuffs but I cannot figure out whether the above sample of code is fine or not. I know the && operator introduces a sequence point so I am not very sure about the behavior of the expression z = x && y && ++z. Someone please tell me the correct answer.

A: 

Yes, it will compile.

But if you are asking about logical bugs:

1) the && operator introduces a sequence point because it could terminate the evaluation of the expression when it knows for sure the final result (in this case a 0 value can terminate the evaluation), so it won't even reach to the ++z part if x or y is zero.

2) because the && operator is a logical one, the result will always be 0 or 1, and I doubt that this is what you wanted.

ruslik
+5  A: 

In C++ 03.

void main(void) 
{ 
  int x,y,z; 
  x=y=z=1;                                  // Seq1 at ;

  z = x && y && ++z;//is this fine?         // Seq2 at ;
} 

NB: Note that there are sequence points at the operator && but then those are not relevant in this example.

Fine!. In general, may be or may be Not. Depends on the values of x and y. In your specific case, it is not fine. This code has the potential to have something called undefined behavior.

If z++ is evaluated (as in your example because x and y are 1), then the scalar variable 'z' is modified more than once in the expression between two sequence points Seq1 and Seq2 (see below). It is important to note that the assignment operator does not introduce any sequence point.

$5/4- "Except where noted, the order of evaluation of operands of individual operators and subexpressions of individual expressions, and the order in which side effects take place, is unspecified.53) Between the previous and next sequence point a scalar 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. The requirements of this paragraph shall be met for each allowable ordering of the subexpressions of a full expression; otherwise the behavior is undefined."

In C++0x

Will update it once I myself understand the details of the discussion referred to by @litb. For now, I am just striking it off

In C++0X however, as I understand, there is no concept of sequence points. This expression is fine and does not invoke undefined behavior. This is because the effect of ++ on 'z' is sequenced before the side effect of assignment on 'z'.

$1.9/15- "Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced. [ Note: In an expression that is evaluated more than once during the execution of a program, unsequenced and indeterminately sequenced evaluations of its subexpressions need not be performed consistently in different evaluations. —end note ] The value computations of the operands of an operator are sequenced before the value computation of the result of the operator. If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined.

$3.9/9 - "Arithmetic types (3.9.1), enumeration types, pointer types, pointer to member types (3.9.2), std::nullptr_t, and cv-qualified versions of these types (3.9.3) are collectively called scalar types."

Note that in the expression 'z = z++;' where z is a scalar variable, the side effects on 'z' due to assignment operator and postfix operator++ are unsequenced (neither of them is sequenced before the other).

Thanks @Prasoon for giving valuable inputs to refine this post from original version

Chubsdad
@Prasoon Saurav: where r you?
Chubsdad
@Chubsdad : The behaviour would be undefined depending on the values of `x` and `y`. But we have `x=1` and `y=1` so the evaluation of `++z` is guaranteed, hence the behaviour would be undefined because `z` is being modified more than once between two sequence points[assignment and preincrement modify `z` twice without any intervening sequence point]. Note that your post contains quote from C++0x draft. In C++0x `i = ++i` is a well defined behaviour.
Prasoon Saurav
Upvoted your answer now. :)
Prasoon Saurav
@Prasoon Saurav: Thanks for your review and expert comments.
Chubsdad
There is no UB, regardless of `x` and `y` values. Check out *ISO 14882-98*, 5.14/2 "Logical AND operator" : "All side effects of the first expression except for destruction of temporaries happen before the second expression is evaluated". Ditto for Logical OR (5.15/2).
atzz
@atzz: Why -1? Your statement would be good for the expression 'int z, y; y = ++z ' and not for the case above because of reasons mentioned in the post.
Chubsdad
@Chubsdad - indeed. It seems I was more distracted than I thought... Mea culpa.
atzz
@Prasoon `i = ++i` is undefined behavior also in C++0x. I don't know what I said the other day about that expression in C++0x. But I discussed such examples on usenet subsequently, and after I rechecked the example I found the wording makes it undefined. The expressions `++i = 0` and `++ ++i` are fine though. In the end we all agreed C++0x makes it defined, but some guys (among them the Standard's editor Pete Becker) doubted that C++0x's intention is to make such things as valid though. See http://groups.google.com/group/comp.lang.c++/browse_thread/thread/97e9767139bebcc6
Johannes Schaub - litb
Likewise, `z = x ` is undefined in C++0x for the same reason: The value computation of `z` in the lhs is not sequenced with the side effect `++` in the lhs. What *is* sequenced is the value computation of the entire rhs relative to the `++`. But this does not imply sequencing of value computation of the lhs relative to the `++` side effect. That would require either direct sequencing of the lhs value computation relative to the `++` or a sequencing of the lhs value computation relative to the value computation of the rhs. Both do not exist.
Johannes Schaub - litb
So to put it into a picture, in `a = ++a` we have: *value_compute(`a`) -> [assign] <- value_compute(`++a`)*. And even finer, *value_compute(`a`) -> [assign] <- (value_compute(`a`) -> [increment a] -> value_compute(`++a`))*, where *`x` -> `y`* means *`x` is sequenced before `y`*. As this shows, there is no order between the left most value computation on a and the *[increment a]*.
Johannes Schaub - litb
I'm sorry for all the confusion I caused :)
Johannes Schaub - litb
@Johannes : Extremely confusing but very interesting. It created suspicions in the minds of so many experts there. Why don't you start a thread here explaining what has been changed in C++0x[...] relative to C++03. The thread can be similar to [this](http://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom). `:)` That would be very beneficial for the members[as well as for the experts] here. `:)`
Prasoon Saurav
@Johannes Schaub - litb: Thanks. It's confusing but thanks for setting us on the right course. I am yet to get a complete feel of this (post which I will update this post).
Chubsdad
@Chubsdad : Yeah it is very confusing indeed. Good'ol sequence points were better [`:P`], the concepts were a bit easier to understand. `:)`
Prasoon Saurav
+2  A: 

A simple way to know if that line is fine or not is let the compiler check that. For example, gcc has the -Wsequence-point option (enabled by -Wall) for checking if there's undefined behavior because of lack of sequence points.

Your program

int main(void)
{
  int x,y,z;
  x=y=z=1;

  z = x && y && ++z;/*is this fine?*/

    return 0;
}

produces this warning:

x.c: In function 'main':
x.c:6:5: warning: operation on 'z' may be undefined
KennyTM
It's frustrating that gcc requires a special option for producing warnings about this instead of just generating `movb $0,0` or equivalent for such code.
R..