4

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 } 
6
  • 1
    as far as i know, the x==1 will be executed last always. or else all my programs would break... :S Commented Jan 13, 2012 at 14:50
  • Does this even compile? Your f takes an int reference, and you are passing an address. Commented Jan 13, 2012 at 14:50
  • Woops, I meant to write int *x. I'll fix it immediately. Commented Jan 13, 2012 at 14:50
  • 1
    I assume you mean *x = 1; though. Commented Jan 13, 2012 at 14:53
  • 1
    The && operator evaluates the expression on the left hand side first, and if true (i.e. true, non NULL and nod nullptr, or any non-zero value) then it evaluates the expression on the right hand side. Commented Jan 13, 2012 at 14:56

7 Answers 7

13

It's not undefined behavior as operator && is a sequence point

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you. For some reason, I wasn't sure that && 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.
7

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 , b 

using the built-in meaning of the operators in these expressions, there is a sequence point after the evaluation of the first expression (12).

5 Comments

Why is it unspecified in this case?
@mattjgalloway Because the compiler gets to choose which order it evaluates its expressions in, presumably for performance purposes.
@MrLister but absolutely not with &&.
Then I don't understand what your question means. Which "it" did you mean, given that quote said "except where noted..."?
To clear the doubts,This is not unspecified behavior.Just for a few seconds I mistook and forgot completely about short circuiting though it was just for few seconds after which I corrected the same.Hmm friday evenings make me drowsy..
2

It is defined. C/C++ do lazy evaluation and it is defined that first the left expression will be calculated and checked. If it is true then the right one will be.

Comments

2

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.

Comments

2

It is not undefined behavior. The reason depends on two facts, both are sufficient for giving defined behavior

  • A function call and termination is a sequence point
  • The '&&' operator is a sequence point

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.

Comments

1

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

Comments

0

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.