8

Which order is the and && operator evaluated

For example the following code

if (float alpha = value1-value2 && alpha > 0.001)
    //do something

threw an exception that alpha is being used without being initiated. I thought the expression left of the && would always initiate the value of alpha first, but it seems I may be wrong

Any idea?

Thanks

Kijewski
  • 25,517
  • 12
  • 101
  • 143
zenna
  • 9,006
  • 12
  • 73
  • 101
  • An odd question, I don't have a textbook. – zenna Jan 20 '10 at 16:24
  • See: http://stackoverflow.com/questions/136548/pro-con-initializing-a-variable-in-a-conditional-statement-c – Shog9 Jan 20 '10 at 16:25
  • 3
    What's the point in comparing an integer to a floating-point literal? You should write `alpha > 0`. It's easier to type, does the same thing, and is clearer. Alternatively, do the comparison with floating-point numbers. – David Thornley Jan 20 '10 at 17:18
  • you are right, it was meant to be a float. – zenna Jan 21 '10 at 00:47

14 Answers14

13

This gets parsed as:

if (int alpha = (value1-value2 && (alpha > 0.001)))

... because && has a higher "parsing precedence" than = -- which is probably not what you want. Try:

int alpha = value1-value2; 
if (alpha && (alpha > 0.001))
Kornel Kisielewicz
  • 55,802
  • 15
  • 111
  • 149
11

The bottom line here is that what you are trying to express cannot be possibly expressed by a single logical condition with the declaration of alpha being embedded into it (despite what some other answers claim).

The other answers already explained to you that your condition is not parsed the way you think it is parsed, although many answers make an obvious error of referring to the precedence of = operator in the condition, while in reality there's no = operator there whatsoever. The correct explanation is that when you declare a variable in the if condition, the syntax is that of declaration with an initializer, so the whole thing is parsed the same way as

int alpha = value1 - value2 && alpha > 0.001;

would be parsed, i.e. it is a declaration of int alpha initialized with value1 - value2 && alpha > 0.001. There's no operator = in it. And I hope now you can see why the compiler says that you are reading an uninitialized variable in the initializer expression. The compiler would make the same complaint on the following declaration

int alpha = alpha; // reading uninitialized variable

for the very same reason.

To achieve what you are literally trying to express, you have to either pre-declare alpha

int alpha;
if ((alpha = value1 - value2) && alpha > 0.001) {
  // whatever 
}

or split your if into two

if (int alpha = value1 - value2) 
  if (alpha > 0.001) {
    // whatever 
  }

However, since the second condition already requires alpha to be greater than 0, it doesn't make much sense to even verify the first one, so the most meaningful thing to do would be to just reduce the whole thing to

int alpha = value1 - value2;
if (alpha > 0.001) {
  // whatever 
}

Of course, as others already noted, the comparison of an int value to 0.001 is a valid, but rather weird thing to do. Just do

int alpha = value1 - value2;
if (alpha > 0) {
  // whatever 
}
AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
4

The left side is always evaluated first. The problem here is operator precedence. See if this doesn't work better:

if ((int alpha = value1-value2) && (alpha > 0.001))
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • 2
    If I am not mistaken, the declaration of `alpha` like that is not permitted in the body of the `if` when it is part of a larger expression. – James McNellis Jan 20 '10 at 16:27
  • 1
    @James:offhand, I don't remember, but you could be right. Under the circumstances, I'd probably use: `int alpha = value1-value2; if (alpha>0.001)` As written, the code also includes a redundant comparison to zero. – Jerry Coffin Jan 20 '10 at 16:31
  • Per this answer here, it is not allowed: http://stackoverflow.com/questions/1516919/1516966#1516966 (took me a while to find it). MSVC++ 2008 and Intel C++ 11.1 both reject it, too. – James McNellis Jan 20 '10 at 16:37
2

After clarifying how it works (for educative purposes), do not do this. Do not mix variable initialization/assignment and comparisons in the same statement.

It is better if each statement is either a "command" or a "query" alone.

And it is much, much better if a condition inside an "if" is very clearly readable, and unequivocally bool. Not integer, no nothing, just bool.

The first part of your condition is an integer. Then you do an and with a bool. You are forcing a conversion with no need at all. Give if's and conditional operators exactly what they ask for: bools.

Daniel Daranas
  • 22,454
  • 9
  • 63
  • 116
2

Answering the question in the title, it depends on the types of the operands.

For builtin-types, && short-circuits, meaning that the LHS is evaluated, and if it is false then the RHS is not evaluated at all.

For user-defined types which have overloaded operator&&, it does not short-circuit. Both sides are evaluated, in unspecified order, and then the function is called.

I think others have handled the question you need answered, though.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • 1
    Which is why I recommend that C++ developers that overload `&&` or `||` or `,` be educated if junior, or shot or fired if senior, depending on which works better under local laws. – David Thornley Jan 20 '10 at 17:16
  • @David Thornley: Not true in general. If the class, for which these operators are overloaded, has no obvious boolean semantics, then you shouldn't (and can't) be making any assumptions about the behavior of overloaded `&&`. – AnT stands with Russia Jan 20 '10 at 18:17
  • 1
    @AndreyT: If there is no obvious boolean semantics, then don't overload random operators. In any case, the fact that `&&` is overloaded is not usually immediately obvious, and overloading changes the fundamental behavior of the operator, removing a sequence point. If I can't look at a statement and see where the sequence points are, somebody has screwed up big-time. – David Thornley Jan 20 '10 at 18:35
  • @David Thornley: It thought you were talking about absence of short-circuit evaluation of overloaded `&&`. The sequence point is a different issue. It is rather replaced with a group of completely different sequence points arranged differently. This could be an issue, I agree. – AnT stands with Russia Jan 20 '10 at 18:41
  • @David: I almost agree with shooting, but overloading `operator,` can be OK when you're in effect inventing a DSL immersed in C++. Just make sure it's obvious in use that this isn't your grandmother's comma operator. I imagine the same could be true of && and ||. They're the lowest-precedence mathematical operators, which maybe is convenient if you must mess with the meanings of anything (precedence of stream operator<< is so arbitrary). As AndreyT says, there are still sequence points. One (well, two) for each function call. – Steve Jessop Jan 20 '10 at 19:07
  • Or another example: you're writing a class representing expressions in propositional calculus. They don't convert to `bool`, but there are obvious and productive meanings of `operator&&` and `operator||`, each returning an object of the same type. Of course they don't short-circuit (what would that even mean), but I doubt this would cause any confusion. As with most operator overloads there isn't a whole lot in it, but I think `Proposition C = A && B;` reads a little better than `Proposition C = and(A,B);`, or `A.and(B);`. – Steve Jessop Jan 21 '10 at 02:25
1

If I'm not mistaken, that operation is undefined. Asigning to to variable and then referring to that same variable in a single statement is undefined.

slebetman
  • 109,858
  • 19
  • 140
  • 171
  • 1
    It's well defined here. `&&` introduces a sequence point, so `alpha` has a determinate value before the second test (after the operator precedence fix of course). – Alok Singhal Jan 20 '10 at 16:25
  • 1
    The problem isn't "in a single statement", but "without an intervening sequence point". Among other things, `&&` *does* impose a sequence point, so when it's used properly it prevents the problem you're thinking of. – Jerry Coffin Jan 20 '10 at 16:26
  • @Alok, What do you expect the "well-defined" value of alpha to be? Sequence point or not, it's still being used uninitialized. – Dan Olson Jan 20 '10 at 16:37
  • @Dan: if `value1` and `value2` are initialized, `if ((alpha = value1 - value2) && (alpha > 0.001))` is well-defined, and `alpha` doesn't get used uninitialized. – Alok Singhal Jan 20 '10 at 16:40
  • I agree, but that's not what the question is about. – Dan Olson Jan 20 '10 at 18:35
  • "Asigning to to variable and then referring to that same variable in a single statement" is perfectly well defined. Otherwise we'd have `a = a + 1` as undefined. The only important thing to watch for here is that the variable should be read for the purpose of determining its new value. – AnT stands with Russia Jan 21 '10 at 00:17
1

I generally always use parenthesis just to make my code a little more clear of my intent.

cquillen
  • 1,287
  • 2
  • 9
  • 14
1

It's evaluated from left to right.

In your case, however the assignment is the last thing to happen and they whole thing would behave as (where alpha is used as part of the calculation to get the result to initialize it):

if (int alpha = (value1-value2 && alpha > 0.001))

You can't mix variable declarations into complex expressions, therefore the following won't compile:

if ((int alpha = value1-value2) && (alpha > 0.001))

Therefore you'll need to split it up to two lines:

int alpha = value1 - value2;
if (alpha > 0.001)
UncleBens
  • 40,819
  • 6
  • 57
  • 90
1
if (int alpha = value1-value2 && alpha > 0.001)

According to the rules would be evaluated in order as

1.  (value1-value2)   [evaluate subtraction]
2.  && (left side)    [test left side]
3.  (alpha > 0.001)   [evaluated only if value-value2 != 0]
4.  && (right side)   [test right side]
4.  alpha =           [assignment]

In step 3, alpha is first evaluated. Since it hasn't been assigned—and maybe not declared, the rules aren't clear on this—it produces an error.

The flaw is that assignment is lower precedence than &&. What still doesn't work, but is closer:

if (int alpha = value1-value2, alpha > 0.001)

Gcc gives error: expected expression before ‘int’. Well maybe it's not closer. With the original statement, gcc says the same thing.

wallyk
  • 56,922
  • 16
  • 83
  • 148
0

My guess is that it's because you're declaring the storage inside the "if" statement. I didn't even think that would compile.

Try this.

int alpha;
if ((alpha=value1-value2) && alpha>0.001)

But I don't think this is doing what you need. You have alpha as an int, and you're then comparing it to a floating point value. The first part of the && statement will retrun true as long as alpha is not zero and the second part will return true if alpha is greater than 0. So you should probably do this

int alpha;
if ((alpha=value1-value2)>0)

or for much more readable code

int alpha=value1-value2
if (alpha>0)

But to answer your original question: && is executed left to right and short circuited when the answer is obvious. I.e., if the first part of the && is false, the second isn't even evaulated!

miked
  • 3,458
  • 1
  • 22
  • 25
0

Here's an article listing operator precedence and associativity.

From what I can tell, your intent is to declare a temporary, assign it the value of value1-value2, then test the result and enter the if block if it is greater than some value. alpha is being declares as an int, but you seem to be comparing it against a double. alpha should be a double.

Your'e being creative with the use of temporaries. Clear is often better than cute. Do this instead:

double alpha = value1-value2;
if (alpha > 0.001)
John Dibling
  • 99,718
  • 31
  • 186
  • 324
0

According to : http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B

- LtR
> LtR
&& LtR
= RtL

given your example

(int alpha = value1-value2 && alpha > 0.001)
(int alpha = (value1-value2) && alpha > 0.001)
(int alpha = (value1-value2) && (alpha > 0.001))
(int alpha = (value1-value2) && (alpha > 0.001))
(int alpha = ((value1-value2) && (alpha > 0.001)))
XAder
  • 676
  • 4
  • 12
0

As written this expression does the following:

  1. Evaluates value1 - value2 and converts it to a bool by implicit comparison against zero - i.e., it is effectively (value1 - value2) != 0
  2. Evaluates alpha > 0.001 after truncating 0.001 to int(0). At this point alpha is not initialized.
  3. Calculates the Logical AND of the previous two evaluations
  4. Converts the Boolean result of the Logical AND back to an integer

I think that this summarizes the rest of the posts. The only reason that I posted a separate answer is that I could not find one that mentioned both when alpha was not initialized and all of the conversions that are occurring here; wallyk's answer is closest.

Of course, the rest of the answers that suggest that you use parentheses and a separate declaration of alpha are exactly what you should do to fix this. Declaring variables within an if statement is part of the language that I haven't found a good use for - declarations within repetition structures seems more appropriate.

Community
  • 1
  • 1
D.Shawley
  • 58,213
  • 10
  • 98
  • 113
-1

The problem is that the statement is evaluating like this:

if (int alpha = (value1-value2 && alpha > 0.001))

Use parentheses to fix the left- and right-hand sides of the && operator:

if ((int alpha = value1-value2) && (alpha > 0.001))

Aaron
  • 6,988
  • 4
  • 31
  • 48