Is a && b && c
defined by the language to mean (a && b) && c
or a && (b && c)
?
Wow, Jerry was quick. To beef up the question: does it actually matter? Would there be an observable difference between a && b && c
being interpreted as (a && b) && c
or a && (b && c)
?
∀a,b,c∈S:(a∨b)∨c=a∨(b∨c) That is, both ∨ and ∧ are associative operations.
The basic Laws of Boolean Algebra that relate to the Commutative Law allowing a change in position for addition and multiplication, the Associative Law allowing the removal of brackets for addition and multiplication, as well as the Distributive Law allowing the factoring of an expression, are the same as in ordinary ...
The right-associativity of the = operator allows expressions such as a = b = c to be interpreted as a = (b = c) .
Operators Associativity is used when two operators of same precedence appear in an expression. Associativity can be either Left to Right or Right to Left. For example: '*' and '/' have same precedence and their associativity is Left to Right, so the expression “100 / 10 * 10” is treated as “(100 / 10) * 10”.
§5.14/1: "The && operator groups left-to-right. [...] Unlike &, && guarantees left-to-right evaluation: the second operand is not evaluated if the first operand is false."
As to when or how it matters: I'm not sure it really does for built-in types. It's possible, however, to overload it in a way that would make it matter. For example:
#include <iostream>
class A;
class M {
int x;
public:
M(int x) : x(x) {}
M &operator&&(M const &r);
M &operator&&(A const &r);
friend class A;
};
class A {
int x;
public:
A(int x) : x(x) {}
A &operator&&(M const &r);
A &operator&&(A const &r);
operator int() { return x;}
friend class M;
};
M & M::operator&&(M const &r) {
x *= r.x;
return *this;
}
M & M::operator&&(A const &r) {
x *= r.x;
return *this;
}
A &A::operator&&(M const &r) {
x += r.x;
return *this;
}
A &A::operator&&(A const &r) {
x += r.x;
return *this;
}
int main() {
A a(2), b(3);
M c(4);
std::cout << ((a && b) && c) << "\n";
std::cout << (a && (b && c)) << "\n";
}
Result:
9
16
Caveat: this only shows how it can be made to matter. I'm not particularly recommending that anybody do so, only showing that if you want to badly enough, you can create a situation in which it makes a difference.
The &&
and ||
operators short-circuit: if the operand on the left determines the result of the overall expression, the operand on the right will not even be evaluated.
Therefore, a mathematician would describe them as left-associative, e.g.a && b && c
⇔ (a && b) && c
, because to a mathematician that means a
and b
are considered first. For pedagogical purposes, though, it might be useful to write a && (b && c)
instead, to emphasize that neither b
nor c
will be evaluated if a
is false.
Parentheses in C only change evaluation order when they override precedence. Both a && (b && c)
and (a && b) && c
will be evaluated as a
first, then b
, then c
. Similarly, the evaluation order of botha + (b + c)
and (a + b) + c
is unspecified. Contrast a + (b * c)
versus (a + b) * c
, where the compiler is still free to evaluate a
, b
, and c
in any order, but the parentheses determine whether the multiplication or the addition happens first. Also contrast FORTRAN, where in at least some cases parenthesized expressions must be evaluated first.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With