I was wondering whether the access to x in the last if below here is undefined behaviour or not:
int f(int *x) { *x = 1; return 1; } int x = 0; if (f(&x) && x == 1) { // something } It's not undefined behavior as operator && is a sequence point
&& would behave differently from , - but that must obviously be the case, since it has the short-circuit property. In my defence, it's Friday afternoon and I need more coffee.&& doesn't behave differently to , the operator which also defines a sequence point, but does behave differently to , the parameter separator which doesn't. Making , a more confusing case.It is well defined.
Reference - C++03 Standard:
Section 5: Expressions, Para 4:
except where noted [e.g. special rules for && and ||], 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.
While in,
Section 1.9.18
In the evaluation of the following expressions
a && b a || b a ? b : c a , busing the built-in meaning of the operators in these expressions, there is a sequence point after the evaluation of the first expression (12).
&&.No, because && defines an ordering in which the lhs must be computed before the rhs.
There is a defined order also on ||, ?: and ,. There is not on other operands.
In the comparable:
int x = 0; if (f(&x) & x == 1) { // something } Then it's undefined. Here both the lhs and rhs will be computed and in either order. This non-shortcutting form of logical and is less common because the short-cutting is normally seen as at least beneficial to performance and often vital to correctness.
It is not undefined behavior. The reason depends on two facts, both are sufficient for giving defined behavior
The following is defined behavior too
int f(int *x) { *x = 1; return 1; } int x = 0; if (f(&x) & (x == 1)) { // something } However, you don't know whether x == 1 evaluates to true or false, because either the first or the second operand of & can be evaluated first. That's not important for the behavior of this code to be defined, though.
It's not undefined, but it shouldn't compile either, as you're trying to assign a pointer to x (&x) to a reference.
&& will be evaluated from left to right (evaluation will stop, if the left side evaluates false).
Edit: With the change it should compile, but will still be defined (as it doesn't really matter if you use a pointer or reference).
It will pass the address of the local variable x in the caller block as a parameter to f (pointer to int). f will then set the parameter (which is a temporary variable on the stack) to address 1 (this causes no problem) and return 1. Since 1 is true, the if () will move on to evaluate x == 1 which is false, because x in the main block is still 0.
The body of the if block will not be executed.
EDIT
With your new version of the question, the body will be executed, because after f() has returned, x in the calling block is 1.
ftakes an int reference, and you are passing an address.*x = 1;though.&&operator evaluates the expression on the left hand side first, and if true (i.e.true, nonNULLand nodnullptr, or any non-zero value) then it evaluates the expression on the right hand side.