In article <ej**********@aioe.server.aioe.org>
marko <ma***@validnow.comwrote:
thing still puzzles me is precedence. The test line contains both logical
operator && , || without parenthesis and && has higher precedence yet left
and right operands of || was evaluated first.
"Precedence" is not "order of evaluation".
Strictly speaking, ANSI/ISO C does not even have "operator precedence"
(it uses a fully-factored grammar instead). It does have "order
of evaluation", though -- and one grammar may be equivalent to
another, so a precedence-free factored grammar can have the same
set of valid productions as an operator-precedence grammar.
Operator-precedence grammars are easier for people (i.e., "you" :-) )
to deal with, so textbooks on C generally use those.
>... when * operator and + operator are presented without parenthesis,
left and right side of * operator evaluates first with associativity
of left to right.
You must memorize this: "precedence is not order of evaluation".
Precedence (which C formally lacks anyway) simply determines which
operator(s) bind to which arguments, in order to build a parse tree
at compile time.
Order of evaluation happens much later, at run time, and -- in C
at least -- is keyed off of things called "sequence points". A
limited set of C operators provide sequence points, specifically
including the logical operators (&& and ||). They dictate that
*once they are evaluated* (whenever that is), first their left side
is evaluated, then a sequence point occurs, then their right side
is evaluated if and only if the result is not yet known.
So, given:
if (f1() || f2() && f3())
the *operator binding* is:
apply && to result of calling f2() and result of calling f3()
and:
apply || to result of calling f1() and result of <bound group>
which can be drawn as the following tree:
||
/ \
f1() &&
/ \
f2() f3()
The tree that *cannot* be drawn (because C does not allow it, either
through a fully-factored grammar that is painful to write out, or
because of an equivalent grammar in your textbook that uses
"operator precedence") is:
&&
/ \
[WRONG] || f3()
/ \
f1() f2()
The runtime *order of evaluation* is required to be:
- call f1, compare its result to zero
- if this produces TRUE (1), take result, do not do the next few:
- call f2, compare result to zero
- if FALSE (0), take result, do not do:
- call f3, compare result to zero
This would be true even if we used parentheses to force the
compile-time binding to match the second tree, by writing:
if ((f1() || f2()) && f3())
However, in this case, the text version of the runtime sequence
might read (pay attention to indentation):
- call f1, compare result to zero
- if this produces TRUE, take result, do not do:
- call f2, compare result to zero
- if result is FALSE, take result, do not do:
- call f3, compare result to zero
In other words, the conditions upon which f3() are called differ
in the second version, even though both versions call f1() first,
then (if at all) f2(), then (if at all) f3().
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it
http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.