Operator precedence is defined in the appropriate standard. The standards for C and C++ are the One True Definition of what exactly C and C++ are. So if you look closely, the details are there. In fact, the details are in the grammar of the language. For example, take a look at the grammar production rule for +
and -
in C++ (collectively, additive-expressions):
additive-expression:
multiplicative-expression
additive-expression + multiplicative-expression
additive-expression - multiplicative-expression
As you can see, a multiplicative-expression is a subrule of an additive-expression. This means that if you have something like x + y * z
, the y * z
expression is a subexpression of x + y * z
. This defines the precedence between these two operators.
We can also see that the left operand of an additive-expression expands to another additive-expression, which means that with x + y + z
, x + y
is a subexpression of it. This defines the associativity.
Associativity determines how adjacent uses of the same operator will be grouped. For example, +
is left-to-right associative, which means that x + y + z
will be grouped like so: (x + y) + z
.
Don't mistake this for order of evaluation. There is absolutely no reason why the value of z
could not be computed before x + y
is. What matters is that it is x + y
that is computed and not y + z
.
For the function call operator, left-to-right associativity means that f()()
(which could happen if f
returned a function pointer, for example) is grouped like so: (f())()
(of course, the other direction wouldn't make any sense).
Now let's consider the example you were looking at:
f1() + f2() * f3()
The *
operator has higher precedence than the +
operator, so the expressions are grouped like so:
f1() + (f2() * f3())
We don't even have to consider associativity here, because we don't have any of the same operator adjacent to each other.
Evaluation of the functions call expressions is, however, completely unsequenced. There's no reason f3
couldn't be called first, then f1
, and then f2
. The only requirement in this case is that operands of an operator are evaluated before the operator is. So that would mean f2
and f3
have to be called before the *
is evaluated and the *
must be evaluated and f1
must be called before the +
is evaluated.
Some operators do, however, impose a sequencing on the evaluation of their operands. For example, in x || y
, x
is always evaluated before y
. This allows for short-circuiting, where y
does not need to be evaluated if x
is known already to be true
.
The order of evaluation was previously defined in C and C++ with the use of sequence points, and both have changed terminology to define things in terms of a sequenced before relationship. For more information, see Undefined Behaviour and Sequence Points.
10 + 10 * 10
- from left to right that's10 + 10 = 20
,20 * 10 = 200
. with proper precedence it's10 + (10 * 10) = 110
. I'm not sure if those operators add a sequence point, so the order of the function execution might be arbitrary. – Crosscheck=
operator inside?:
operator, which means that precedence rules of C and C++ are different. Any table that claims to apply to both C and C++ is inaccurate. And secondly, the precedence properties of?:
operator can't generally be linearized, meaning that any linear table will always be inaccurate with regard to?:
operator. – Daltondaltonism?:
in C++? – Furiea ? b : c = d
, which is grouped as(a ? b : c) = d
in C (leading to a compile error) and asa ? b : (c = d)
in C++. – Daltondaltonism?:
operator actually have different relative precedence with regard to other operators. In case of C the example with assignment operator in the middle segment illustrates it. In C++ the the example with assignment operator in the last segment illustrates it. I.e. assignment in the first segment always has lower precedence, while assignment in the middle and/or last segment seems to have higher precedence. – Daltondaltonisma ? b : c = d
is not grouped as(a ? b : c) = d
in C? – Daltondaltonisma ? b : c = d
does not match any C grammar rule. It is not an expression. Those compilers that use non-standard grammar, have to group it that way to make sure the resulting expression is ill-formed under C's semantics, which also assigns ?: higher precedence. I said I was being pedantic there. – Furie