Short circuit evaluation of a statement with ++ operator in C - c

I have executed the following code in Code::Blocks 10.05 on Windows 7.
int a=0,b=0,c;
c=a++&&b++;
printf("\na=%d\nb=%d\nc=%d\n\n",a,b,c);
The output I obtained is given below,
a=1
b=0
c=0
This makes perfect sense because of short circuit evaluation.
The expression a++ is post increment and 0 is returned to the logical and (&&). Hence the part b++ is not evaluated since both 0 && 0 and
0 && 1 evaluates to 0.
But here arises my doubt. The precedence value of operators clearly states that ++ is having higher precedence over &&. So my understanding was like this, both a++ and b++ are evaluated and then && only checks the result of expression a++ to come to a decision. But this has not happened only a++ is evaluated here.
What is the reason for this behavior? Does && being a sequence point has something to do with this behavior? If so why we say that && is having lower precedence than ++?

You are confused about precedence and order of evaluation.
Precedence defines how the operators are grouped, i.e
c = a++ && b++;
is equivalent to:
c = ((a++) && (b++));
Order of evaluation defines how the expression is evaluated, the short circuit of && means a++ is evaluated first, if it's zero, the end; if it's not zero, b++ is then evaluated.
As another example:
c = (a++) + (b++);
Is a++ evaluated before b++? The answer is we don't know. Most operators don't define the order of evaluation. && is one of the few operators that do define. (The rest are ||, , and ?:)

There are two concepts here - order of precedence and order of evaluation. Order of precedence will have an impact only if an expression (or sub-expression) is evaluated.
In general, the order of evaluation is not sequenced. Given an operator, its operands can be evaluated in any order. The arguments of a function can be evaluated in any order.
From the C++ Standard:
1.9 Program execution
15 Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced.
and
8.3.6 Default arguments
9 Default arguments are evaluated each time the function is called. The order of evaluation of function arguments is unspecified.
For the logical AND operator, &&, the C++11 standard says:
5.14 Logical AND operator
1 The && operator groups left-to-right. The operands are both contextually converted to type bool (Clause 4). The result is true if both operands are true and false otherwise. Unlike &, && guarantees left-to-right evaluation: the second operand is not evaluated if the first operand is false.
Similar exception is specified for the logical OR operator, ||.
Since b++ is not evaluated due to short circuiting of the expression because of && operator, the order of precedence of the operators has no significance in this particular case.

Related

() has the highest priority, why is it short-circuited?

() has the highest priority, why is it short-circuited?
int a = 1, b = 0;
(--a)&&(b++);
Why is (b++) still short-circuited?
I don't find the term "short-circuit" particularly helpful.
It is better to say that && and || have left-to-right order of evaluation. The C standard (6.5.13) actually explains this well:
the && operator guarantees left-to-right evaluation ...
If the first operand compares equal to 0, the second
operand is not evaluated.
And that's it. The left operand --a evaluates to 0.
What is the difference between operator precedence and order of evaluation?
In this case, all that matters is order of evaluation. Operator precedence only guarantees that the expression is parsed as expected - which operands that "glue" to which operator.
The expression (--a) uses the prefix operator and evaluates to 0. This is false and the 2nd expression is not evaluated due to short-circuit as you noted.
To understand consider the following expression
a * b + c * d
If to assume that the operands of the operator + are evaluated from left to right then at first the expression a * b will be evaluated and then the expression c * d.
The assumption relative to the order of evaluations of operands of the operator + is not valid. But it is valid for the operator &&.
So left operand of the expression
(--a)&&(b++);
is evaluated first. And if its value is not equal to 0 then the second operand is evaluated.
From the C Standard (6.5.13 Logical AND operator)
4 Unlike the bitwise binary & operator, the && operator guarantees
left-to-right evaluation; if the second operand is evaluated, there
is a sequence point between the evaluations of the first and second
operands. If the first operand compares equal to 0, the second operand
is not evaluated.
You are right that you can override operator precedence using parenthesis ().
For example, the expression
a && b || c
is equivalent to
(a && b) || c,
because && has a higher precedence than ||. You can override this precedence by changing it to
a && (b || c)
so that now the || has precedence over &&.
However, operator procedence doesn't change the behavior of the individual operators. In particular, both operators will still use short-circuiting. So, even if || has higher precedence than &&, the && operator will still evaluate its left-hand operand before its right-hand operand.
In both of my examples above, the && operator will still evalulate a before evaluating b or (b || c). Operator precedence will only affect whether the right-hand operand of the && operator is the expression b or (b || c).
Therefore, in your example, by writing (--a)&&(b++) instead of --a&&b++, you are merely ensuring that the -- and ++ operators have precedence over the && operator. This is not necessary, because he C language specifies that these operators already have precedence.
In the hypothetical scenario that the C language had instead specified that the && operator had precedence over the -- and ++ operators, then the expression --a&&b++ would be interpreted as --(a&&b)++, and it would be necessary to write (--a)&&(b++) to prevent this interpretation. But this is not the case.

C Operators and Precedence

I'm using C language, for the below code:
#include <stdio.h>
int main(int argc, char const *argv[])
{
int num1=0;
int res = ++num1 && num1++;
printf("%d\t%d\n",num1,res);
}
In the above code I get output as 2 1. I think the output should be 2 0.
Please correct me if wrong, to solve this statement, the num1++(0) would be executed first due to highest precedence and then ++num1(2) would be executed and then at last && will be preformed because it has the lowest precedence.
Please comment how is this statement getting executed.
In some of the tutorials I find that postfix ++ and prefix ++ have the same precedence, but if that is true then according to the associativity rule again num1++ should be executed first(right to left) which should again lead to answer as 2 0.
In the expression used as an initializer
int res = ++num1 && num1++;
there is a sequence point for the operator &&.
From the C Standard (6.5.13 Logical AND operator)
3 The && operator shall yield 1 if both of its operands compare
unequal to 0; otherwise, it yields 0. The result has type int.
and
4 Unlike the bitwise binary & operator, the && operator guarantees
left-to-right evaluation; if the second operand is evaluated, there is
a sequence point between the evaluations of the first and second
operands. If the first operand compares equal to 0, the second operand
is not evaluated.
At first the left operand of the operator is evaluated and as a result num1 will be equal to 1 due to the unary (prefix) increment operator. As the sub-expression is not equal to 0 then the second operand is evaluated. Its value is the value before incrementing that is 1. As this second operand is also unequal to 0 then the whole expression is evaluated to the logical true and its value is 1 (see the first quote from the C Standard).
This value 1 is assigned to the variable res while the variable num1 after the postfix increment will be equal to 2.
So you will have that after this declaration res is equal to 1 and num1 is equal to 2.
Lots of misconceptions here. First of all, operator precedence states the order of parsing, not the order of execution. There are two related but different terms, operator precedence and order of evaluation.
See What is the difference between operator precedence and order of evaluation?.
Once you understand order of evaluation, the && operator specifically comes with well-defined sequencing, which isn't normally the case for C operators. It guarantees a left-to-right order of evaluation. C17 6.5.14/4:
Unlike the bitwise | operator, the || operator guarantees left-to-right evaluation; if the
second operand is evaluated, there is a sequence point between the evaluations of the first
and second operands. If the first operand compares unequal to 0, the second operand is
not evaluated.
Normally, you wouldn't be able to wild and crazy things with the ++ operator mixed with other operators, but the above && rule makes it possible in this specific case.
See Why can't we mix increment operators like i++ with other operators? It explains sequencing/sequence points.
In some of the tutorials I find that postfix ++ and prefix ++ have the same precedence,
They don't, prefix ++ takes precedence over postfix (and other unary operators). So associativity does not apply.
Please correct me if wrong, to solve this statement, the num1++(0) would be executed first due to highest precedence and then ++num1(2) would be executed and then at last && will be preformed because it has the lowest precedence.
Precedence only controls which operators are grouped with which operands - it does not affect the order in which expressions are evaluated.
The &&, ||, ?:, and comma operator all force left-to-right evaluation - the left operand is fully evaluated (and any side effects applied) before the right operand. && and || both short circuit - for &&, the right operand will be evaluated only if the left operand is non-zero.
The unary (prefix) ++ operator yields the current value of the operand plus 1, so the result of ++num1 is 1. As a side effect the value in num1 is incremented. Since this result is non-zero, num1++ is also evaluated. The postfix ++ operator yields the current value of the operand, so the result of num1++ is 1. As a side effect the value in num1 is incremented.
The result of an && expression is 1 if both operands are non-zero, 0 otherwise.
It's roughly equivalent to writing
tmp = num1 + 1;
num1 = num1 + 1;
res = 0;
if ( tmp != 0 )
{
if ( num1 != 0 )
{
res = 1;
}
}
num1 = num1 + 1;
So the result of ++num1 && num1++ is 1, and the value stored in num1 at the end of it is 2.
In some of the tutorials I find that postfix ++ and prefix ++ have the same precedence,
That is very wrong and you should stop using those tutorials immediately. Postfix operators have higher precedence than unary operators - *a++ is parsed as *(a++), ++a[i] is parsed as ++(a[i]), etc. An expression like ++i++ would be parsed as ++(i++), but you can't write such an expression in C - the result of i++ isn't an lvalue and cannot be the operand of a unary ++ like that.

Do '&&' and '||' lie on same row in operator precedence or in different row?

If they do lie in different row then shouldn't in Exp1 || Exp2 && Exp3, (Exp2 && Exp3) be evaluated first since && has higher precedence than ||?
And, If they do lie in same row then shouldn't order of execution be First (Exp1 || Exp2) and then && Exp3 since both are left associative?
Exp1 || Exp2 && Exp3 is grouped as Exp1 || (Exp2 && Exp3), due to operator precedence.
Note that (Exp2 && Exp3) is only actually evaluated if Exp1 evaluates to 0, and then Expr3 is only evaluated if Exp2 evalutes to 1. This is called short-circuiting.
Their being in a different "row" is not relevant.
Operator precedence in C is "as indicated by the syntax", meaning in plain English that each sub chapter of the standard chapter 6.5 is one operator group. The precedence is: first group, highest precedence:
6.5 Expressions
6.5.1 Primary expressions
6.5.2 Postfix operators
6.5.3 Unary operators
6.5.4 Cast operators
6.5.5 Multiplicative operators
6.5.6 Additive operators
6.5.7 Bitwise shift operators
6.5.8 Relational operators
6.5.9 Equality operators
6.5.10 Bitwise AND operator
6.5.11 Bitwise exclusive OR operator
6.5.12 Bitwise inclusive OR operator
6.5.13 Logical AND operator
6.5.14 Logical OR operator
6.5.15 Conditional operator
6.5.16 Assignment operators
6.5.17 Comma operator
As you can see, Logical AND is a separate group from Logical OR. It appears earlier in the standard so it has higher precedence.
If they had been "in the same row", that is if they would have the same precedence, then the operator associativity would determine how the expression should be parsed. a || b || c must be parsed as (a || b) || c because the associativity of this operator group is left-to-right.
Note that operator precedence only mandates which operands that belong with which operators. It doesn't specify order of evaluation (execution), which is a different but related term.
In your case, operator precedence specifies that Exp1 || Exp2 && Exp3 is equivalent to
Exp1 || (Exp2 && Exp3)
The order of evaluation of the || operator specifically is a special case, it must evaluate Exp1 completely first, and if it is false, and only then, evaluate the right-hand operator.
Usually in C, the order of evaluation of operands is not specified though. Take for example Exp1 | Exp2, where no special rule of order of evaluation exists. Then either Exp1 or Exp2 could be evaluated first.

Ambiguous operator precedence, please explain why operator predence is not followed here? [duplicate]

This question already has answers here:
Why does "++x || ++y && ++z" calculate "++x" first, even though operator "&&" has higher precedence than "||"
(11 answers)
Closed 9 years ago.
x = y = z = 1;
z = ++x||++y&&++z;
operator precedence is as follows --
(pre-increment) > && > ||
so answer should be--
1. 2||2 && 2
2. 2||1
3. 1
print x,y,z should be 2,2,1
but, answer is 2,1,1.
Precedence is not the same as order of evaluation. Precedence simply determines what operands and operators belong together. The exact order of evaluation is unspecified except with the logical operators, which are evaluated in strict left-to-right order to enable short-circuiting.
So because && has higher precedence, the variables are first grouped as follows:
(++x) || (++y && ++z)
Then, following left-to-right order, ++x is evaluated. Given that ++x is true, it is known that the entire expression is true. So expression evaluation is short-circuited. (++y && ++z) never gets evaluated. Hence y and z never get incremented.
Expressions with logical operators && and || evaluate left to right:
C99, Section 6.5.14-4 Unlike the bitwise | operator, the || operator guarantees left-to-right evaluation; there is a sequence point after the evaluation of the first operand. If the first operand compares unequal to 0, the second operand is not evaluated.
Since x++ is not zero, the expression short-circuits evaluation of everything to the right of ||, including their side effects. That's why only x++ is evaluated, so x becomes 2. The remaining variables stay at 1, as they should.
There's no sequence point in the expression:
z = ++x || ++y && ++z;
between the pre-increment of z and assignment to z.
So, if the ++z is actually evaluated, that puts you instantly into undefined behaviour territory and anything can happen. You are not permitted to modify the same object twice without an intervening sequence point. Annex C (from C99) lists all the sequence points and the controlling one here is following a full-expression (the entire calculation and assignment).
6.5 Expressions /2 states:
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.
However, given your initial value of x as 1, the ++z part of the expression is not evaluated, in this particular case. That doesn't make the expression itself any less dangerous since it will invoke UB in the case where the starting point is x == -1 and y != -1.
In this case, the controlling part of the standard is 6.5.14 Logical OR operator /4:
Unlike the bitwise | operator, the || operator guarantees left-to-right evaluation; there is a sequence point after the evaluation of the first operand. If the first operand compares unequal to 0, the second operand is not evaluated.
So, the ++x is evaluated first and, because it evaluates to not-zero, ++y && ++z is never evaluated. x is incremented to 2 and z is set to the "truthy" value of that, or 1, y remains untouched at 1.

Is a parenthesis in an expression evaluated before anything else?

In C, the order of evaluation of operands has nothing to do with operator precedence and associativity.
Suppose I have an expression in C: expr1 * expr2 + (expr3 + expr4) (no sequence points in between).
When this expression is evaluated then:
Will sub-expressions expr3 and expr4 be evaluated before expr1 and
expr2 because of the parenthesis?
Or does the parenthesis ensure that operators inside the parenthesis are evaluated before the operators outside the parenthesis?
Do the parentheses ensure order of evaluation of operands or operators?
From the online draft of the 2011 language standard:
6.5 Expressions
...
3 The grouping of operators and operands is indicated by the syntax.85) Except as specified
later, side effects and value computations of subexpressions are unsequenced.86)
85) The syntax specifies the precedence of operators in the evaluation of an expression, which is the same as the order of the major subclauses of this subclause, highest precedence first. Thus, for example, the expressions allowed as the operands of the binary + operator (6.5.6) are those expressions defined in
6.5.1 through 6.5.6. The exceptions are cast expressions (6.5.4) as operands of unary operators
(6.5.3), and an operand contained between any of the following pairs of operators: grouping
parentheses () (6.5.1), subscripting brackets [] (6.5.2.1), function-call parentheses () (6.5.2.2), and
the conditional operator ? : (6.5.15).
Within each major subclause, the operators have the same precedence. Left- or right-associativity is
indicated in each subclause by the syntax for the expressions discussed therein.
86) 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.
Clear as mud, right? What it means is that, given an expression like
x = a++ + b++ * (--c / ++d)
each of the subexpressions a++, b++, --c, and ++d may be evaluated in any order; just because --c and ++d are grouped by parens doesn't mean they're evaluated first. Furthermore, the side effects of each ++ and -- don't have to be applied immediately after the expression is evaluated.
All operator precedence guarantees is that the result of --c / ++d will be multiplied by the result of b++, and the result of a++ will be added to that value; it does not guarantee that any expression is evaluated before any other.
Pay close attention to footnote 86; if the above expression appeared in a loop, there's no reason to expect that the subexpressions would be evaluated in the same order every time through the loop. As a practical matter, they most likely will be, but the compiler is explicitly given the freedom to shake things up.
Because of this freedom to evaluate expressions and apply side effects in any order, certain expressions like a++ + a++ won't give consistent results; the standard explicitly calls this out as undefined behavior, meaning the compiler isn't obligated to handle the situation in any particular way. It can ignore the issue, it can issue a warning, it can halt translation with an error, etc., but there's no requirement that it do any one particular thing.
1.will sub expressions expr3 and expr4 be evaluated before expr1 and expr2 becoz of paranthesis?
No. The evaluation order of expr1, expr2, expr3 and expr4 is unspecified by the C standard. The compiler can evaluate these sub-expressions in any order it prefers, and can interleave them with the operator evaluation if it wants.
2.or paranthesis ensures that operators in paranthesis will be evaluated before than operators outside the paranthesis?
Yes. The parentheses will override the operator precedence from the normal (((expr1 * expr2) + expr3) + expr4) to ((expr1 * expr2) + (expr3 + expr4)). This just determines in which relative order the operators are evaluated.
It can help to show the evaluation order constraints as a tree :
+
________|________
* +
____|____ ____|____
expr1 expr2 expr3 expr4
The evaluation of a node in this tree requires that its children have been evaluated already. But that's the only restriction.
The evaluation order could be : expr2, expr3, expr4, +, expr1, *, +.
Or it could be : expr4, expr3, +, expr1, expr2, *, +.
Or any other permutation that fits the restriction mentioned above.
The parentheses guarantee that what's inside them is evaluated before anything that depends on them. No more.
In your example, (expr3+expr4) is evaluated before the + that adds it to expr1*expr2. It doesn't mean that it's evaluated before expr1*expr2.

Resources