Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Precedence Misunderstanding

Reply
Thread Tools

Precedence Misunderstanding

 
 
Charles Richmond
Guest
Posts: n/a
 
      07-17-2012
Consider the following program:

#include <stdio.h>
#include <stdlib.h>

int main()
{
int i = 4, j = 12, k = 41;

printf("expression is %d + %d * %d\n",k,j,i);
printf("--> value is %d\n",k + j * i);
}

When compiled and run, the output was:

expression is 41 + 12 * 4
--> value is 89

Because the multiply operator has a *higher* precedence than the
addition operator... the multiply is done first. So the result is
89, and *not* 212.


Now take the following program:

#include <stdio.h>
#include <stdlib.h>

int callthis();

int main()
{
int i = 1, j = 1, k = 0;

printf("expression is %s\n","i || j && k");
printf("--> value is %d\n",i || j && k);

printf("expression is %s\n","i || j && callthis()");
printf("--> vnext is %d\n",i || j && callthis());
}

int callthis()
{
printf("--> The function is called.\n");

return 1;
}

When compiled and run, the output was:

expression is i || j && k
--> value is 1
expression is i || j && callthis()
--> vnext is 1


The point I'm making is: The Good Book (K&R II) says that
"logical and" (&&) has a *higher* precedence that "logical or"
(||). And that same Good Book says that a series of "logical and"
and "logical or" operations will occur left to right.

And so it is... left to right evaluation. But *how* then does the
"logical and" have a *higher* precedence than "logical or"... when
this is ignored in the series of AND's and OR's???

(Yes, yes... I know about "short circuit" operators. But I
thought this was operator by operator. In other words, if in the
"i || j && callthis()", *if* the AND were done first [it's
*not*]... and if "j" were FALSE, callthis() would *not* be done.

The actual evaluation is "i || j" done first... if "i" is TRUE,
the the *entire* rest of the expression is short circuited.

Can someone explain how "&&" can have a *higher* precedence than
"||"... when the series of AND's and OR's are just going to be
done left to right???

I *thought* I understood C pretty well... guess not.

--

numerist at aquaporin4 dot com

 
Reply With Quote
 
 
 
 
Stefan Ram
Guest
Posts: n/a
 
      07-17-2012
Charles Richmond <(E-Mail Removed)> writes:
>The point I'm making is: The Good Book (K&R II) says that
>"logical and" (&&) has a *higher* precedence that "logical or"
>(||). And that same Good Book says that a series of "logical and"
>and "logical or" operations will occur left to right.


This quoted paragraph alone might have been sufficient to
make your point. I guess, the above quote means:

- a series of "logical and" operations will occur left
to right.

- a series of "logical or" operations will occur left to
right.

(I'd write »logical-and operation« and »be evaluated« instead
of »occur«.)

 
Reply With Quote
 
 
 
 
Ben Pfaff
Guest
Posts: n/a
 
      07-17-2012
Charles Richmond <(E-Mail Removed)> writes:

> Can someone explain how "&&" can have a *higher* precedence than
> "||"... when the series of AND's and OR's are just going to be done
> left to right???


I think there's a lot of confusion on this point because we
aren't taught about this in our math classes. That's because
side effects don't exist in math, so order of evaluation doesn't
matter. Precedence does, but that's a different issue.

Consider 2 * 3 + 4 * 5. Precedence says that this must be
treated the same as (2 * 3) + (4 * 5). But once you figure that
out, you have a choice: you can evaluate 2 * 3 first or you can
evaluate 4 * 5 first, because the order doesn't matter. No one
bothers to say that you have to evaluate left-to-right or even
that you have to evaluate right-to-left, because that would not
change the eventual result in any way.

When side effects come in, the situation changes. a() + b()
might do something completely different depending on which of a()
or b() you call first. Extending it to a() + b() * c(), then
precedence comes in. C doesn't say in what order a(), b(), and
c() are evaluated, but it does say that once they are evaluated,
you have to multiply b() by c(), not by a().

I hope that helps.
 
Reply With Quote
 
Stefan Ram
Guest
Posts: n/a
 
      07-17-2012
Ben Pfaff <(E-Mail Removed)> writes:
>I think there's a lot of confusion on this point because we
>aren't taught about this in our math classes. That's because
>side effects don't exist in math, so order of evaluation doesn't
>matter. Precedence does, but that's a different issue.


I was taught about associativity already in elementary school IIRC.
After all, you need to know whether 2-3-4 is (2-3)-4 or 2-(3-4).

Effects add the additional twist that, even though one knows that
»f() + g() + h()« means ( f() + g () )+ h(), that does /not/ imply
that »h()« is evaluated last in time.

 
Reply With Quote
 
Ben Pfaff
Guest
Posts: n/a
 
      07-17-2012
http://www.velocityreviews.com/forums/(E-Mail Removed)-berlin.de (Stefan Ram) writes:

> Ben Pfaff <(E-Mail Removed)> writes:
>>I think there's a lot of confusion on this point because we
>>aren't taught about this in our math classes. That's because
>>side effects don't exist in math, so order of evaluation doesn't
>>matter. Precedence does, but that's a different issue.

>
> I was taught about associativity already in elementary school IIRC.
> After all, you need to know whether 2-3-4 is (2-3)-4 or 2-(3-4).


That's just another aspect of precedence. The evaluation of each
function call in a()-b()-c() isn't any more strictly ordered than
a()+b()*c().
 
Reply With Quote
 
Stefan Ram
Guest
Posts: n/a
 
      07-17-2012
Ben Pfaff <(E-Mail Removed)> writes:
>(E-Mail Removed)-berlin.de (Stefan Ram) writes:
>>I was taught about associativity already in elementary school IIRC.
>>After all, you need to know whether 2-3-4 is (2-3)-4 or 2-(3-4).

>That's just another aspect of precedence.


Associativity is not an »aspect of precedence«. Precedence
and associativity are treated as two separate concerns.

»In programming languages and mathematical notation, the
associativity (or fixity) of an operator is a property
that determines how operators of the same precedence are
grouped in the absence of parentheses.«

http://en.wikipedia.org/wiki/Operator_associativity

Of course, the terms are usually not used in N1570,
because there it is all encoded in the grammar.

(Sequencing is yet another story that you should keep
separate from identifying subexpressions of an expression.)

 
Reply With Quote
 
Ben Pfaff
Guest
Posts: n/a
 
      07-17-2012
(E-Mail Removed)-berlin.de (Stefan Ram) writes:

> Ben Pfaff <(E-Mail Removed)> writes:
>>(E-Mail Removed)-berlin.de (Stefan Ram) writes:
>>>I was taught about associativity already in elementary school IIRC.
>>>After all, you need to know whether 2-3-4 is (2-3)-4 or 2-(3-4).

>>That's just another aspect of precedence.

>
> Associativity is not an »aspect of precedence«. Precedence
> and associativity are treated as two separate concerns.


I may be misusing the term--your evidence seems good to me--but
the point that I was making remains: whether 2-3-4 is (2-3)-4 or
2-(3-4) is a separate issue from the order in which each operand
is evaluated.
 
Reply With Quote
 
Ike Naar
Guest
Posts: n/a
 
      07-17-2012
On 2012-07-17, Charles Richmond <(E-Mail Removed)> wrote:
> #include <stdio.h>
> #include <stdlib.h>
>
> int callthis();
>
> int main()
> {
> int i = 1, j = 1, k = 0;
>
> printf("expression is %s\n","i || j && k");
> printf("--> value is %d\n",i || j && k);
>
> printf("expression is %s\n","i || j && callthis()");
> printf("--> vnext is %d\n",i || j && callthis());
> }
>
> int callthis()
> {
> printf("--> The function is called.\n");
>
> return 1;
> }
>
> When compiled and run, the output was:
>
> expression is i || j && k
> --> value is 1
> expression is i || j && callthis()
> --> vnext is 1
>
>
> The point I'm making is: The Good Book (K&R II) says that
> "logical and" (&&) has a *higher* precedence that "logical or"
> (||). And that same Good Book says that a series of "logical and"
> and "logical or" operations will occur left to right.
>
> And so it is... left to right evaluation. But *how* then does the
> "logical and" have a *higher* precedence than "logical or"... when
> this is ignored in the series of AND's and OR's???
>
> (Yes, yes... I know about "short circuit" operators. But I
> thought this was operator by operator. In other words, if in the
> "i || j && callthis()", *if* the AND were done first [it's
> *not*]... and if "j" were FALSE, callthis() would *not* be done.
>
> The actual evaluation is "i || j" done first... if "i" is TRUE,
> the the *entire* rest of the expression is short circuited.
>
> Can someone explain how "&&" can have a *higher* precedence than
> "||"... when the series of AND's and OR's are just going to be
> done left to right???
>
> I *thought* I understood C pretty well... guess not.


Operator precedence is more about defining which operands
are associated with each operator, than it is about defining
order of evaluation.
And, not only operators are evaluated, but so are operands.

In the case of, say "a() + b() * c()", operator precedence
implies that the expression is parsed as

+
a() *
b() c()

that is, the toplevel operation is "+", with operands "a()"
and the sub-expression "b() * c()".
Now, before the "+" operator can be applied, first its operands
"a()" and "b() * c()" must be evaluated. The order in which "a()" and
"b() * c()" are evaluated is unspecified, so "a()" may be evaluated
first, or "b() + c()" may be.

The evaluation of "b() * c()" consists of evaluating "b()" and
"c()", in either order, and then applying the "*" operator to the
results of evaluating "b()" and "c()".

So, in the end, many orders of evaluation are possible, e.g.

a(), b(), c(), *, +
a(), c(), b(), *, +
b(), c(), *, a(), +
c(), b(), *, a(), +

In "i || j && callthis()", operator precedence implies
that the expression is parsed as

||
i &&
j callthis()

that is, the top-level operation is "||" and its operands
are "i" and "j && callthis()".
Now the short-circuit rule for "||" says that its left operand "i"
is evaluated first, and, since the result is nonzero, the outcome
of the "||" operation is known to be 1, and the right operand
"j && callthis()" is never evaluated.

If i would have been zero, then the subexpression "j && callthis()"
would have to be evaluated before applying "||" to the result of "i"
and "j && callthis()".

And the evaluation of "j && callthis()" would consist of
evaluation of "j" first (because of the short-circuit rule
for "&&"). If "j" would be zero, the outcome of the "&&" would
be 0 and and right hand side "callthis()" would never be evaluated.
Only if "j" would be nonzero, "callthis()" would be evaluated.
 
Reply With Quote
 
Ben Bacarisse
Guest
Posts: n/a
 
      07-17-2012
Ben Pfaff <(E-Mail Removed)> writes:

> (E-Mail Removed)-berlin.de (Stefan Ram) writes:
>
>> Ben Pfaff <(E-Mail Removed)> writes:
>>>(E-Mail Removed)-berlin.de (Stefan Ram) writes:
>>>>I was taught about associativity already in elementary school IIRC.
>>>>After all, you need to know whether 2-3-4 is (2-3)-4 or 2-(3-4).
>>>That's just another aspect of precedence.

>>
>> Associativity is not an »aspect of precedence«. Precedence
>> and associativity are treated as two separate concerns.

>
> I may be misusing the term--your evidence seems good to me--but
> the point that I was making remains: whether 2-3-4 is (2-3)-4 or
> 2-(3-4) is a separate issue from the order in which each operand
> is evaluated.


In some ways I don't think you are misusing the term, although common
usage has certainly decided that separating precedence and associativity
makes life simpler for most programming languages. Some parser
generators dispense with this distinction by allow an operator to have
two precedences -- a left precedence and a right precedence. This
allows associativity to be folded into the concept of precedence. There
are also languages where you need this concept to understand how to
parse its expressions. Perl's list operators, for example, have highly
asymmetric left and right precedence so they can't be described using
the common notions of precedence and associativity.

--
Ben.
 
Reply With Quote
 
Charles Richmond
Guest
Posts: n/a
 
      07-17-2012
"Ben Pfaff" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> Charles Richmond <(E-Mail Removed)> writes:
>
>> Can someone explain how "&&" can have a *higher* precedence than
>> "||"... when the series of AND's and OR's are just going to be done
>> left to right???

>
> I think there's a lot of confusion on this point because we
> aren't taught about this in our math classes. That's because
> side effects don't exist in math, so order of evaluation doesn't
> matter. Precedence does, but that's a different issue.
>
> Consider 2 * 3 + 4 * 5. Precedence says that this must be
> treated the same as (2 * 3) + (4 * 5). But once you figure that
> out, you have a choice: you can evaluate 2 * 3 first or you can
> evaluate 4 * 5 first, because the order doesn't matter. No one
> bothers to say that you have to evaluate left-to-right or even
> that you have to evaluate right-to-left, because that would not
> change the eventual result in any way.
>
> When side effects come in, the situation changes. a() + b()
> might do something completely different depending on which of a()
> or b() you call first. Extending it to a() + b() * c(), then
> precedence comes in. C doesn't say in what order a(), b(), and
> c() are evaluated, but it does say that once they are evaluated,
> you have to multiply b() by c(), not by a().
>


Mr. Pfaff, I *do* understand about "side effects" with expression evaluation
in programming languages. I understand *why* short circuiting and
guaranteeing the order of execution... *can* be helpful at times.

The crux of what I do *not* understand is this:

Can someone explain how "&&" can have a *higher* precedence than
"||"... when any series of AND's and OR's are just going to be
done left to right???

For example, if you have a long series of logical AND's and OR's like this:

a && b || c || d && x && y || z

How will "&&" having a higher precedence than "||" effect this at all???
ISTM that evaluation would be the *same* if "&&" and "||" were of equal
precedence.

Create any series of AND's and OR's you want, and please show me how the
precedence of "&&'" and "||" will make any difference under the current C
standard.

Also ISTM that in the above expression, it will *not* matter if one adds
parentheses around any operator/operand pair or grouping. The result seems
to be the same. Please show me where I'm wrong.

I can *not* understand how "&&" can have a higher precedence than "||"...
when it seems to make *no* difference in *any* expression I've seen.

--

numerist at aquaporin4 dot com


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
vec - a misunderstanding Mark Hobley Perl 1 03-18-2006 07:32 PM
Misunderstanding ConnectionStrings? Shawn Wildermuth ASP .Net 6 01-11-2006 02:57 AM
View State Misunderstanding Philip Tripp ASP .Net 3 07-26-2004 04:13 PM
errors in book or my misunderstanding? David K MCSE 4 12-12-2003 03:22 PM
Re: Class property misunderstanding Kevin Spencer ASP .Net 1 06-26-2003 05:28 PM



Advertisments