Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

*p++

7 views
Skip to first unread message

dac

unread,
May 11, 2001, 5:41:07 PM5/11/01
to
This is supposed to return the value pointed by p, and then increment p,
right?
My problem is that, looking at the precedence table, I can't seem to
understand it.
++ has greater precedence than *, and both evaluate from right to left.
So, in *p++ shouldn't ++ be evaluated first, and then dereferenced?

So, for example, having

char *p = "Hello";

printf("%c", *p++);

shouldn't return 'e' ?

Or the compiler "realizes" that being a postincrement, it has to be
"executed" last?

--
Greetings,
David.

(When replying please remove all numbers to my email address.)

Mark McIntyre

unread,
May 11, 2001, 6:35:32 PM5/11/01
to
On Fri, 11 May 2001 18:41:07 -0300, "dac" <ac...@turdera.com.ar> wrote:

>This is supposed to return the value pointed by p, and then increment p,
>right?

Yes.


>My problem is that, looking at the precedence table, I can't seem to
>understand it.
>++ has greater precedence than *, and both evaluate from right to left.
>So, in *p++ shouldn't ++ be evaluated first, and then dereferenced?

No. Are you confusing the * multiplication operator and the *
dereferencing operator ?

>So, for example, having
>
>char *p = "Hello";
>
>printf("%c", *p++);
>
>shouldn't return 'e' ?

It should not return 'e', and does not

--
Mark McIntyre
CLC FAQ <http://www.eskimo.com/~scs/C-faq/top.html>

Des Walker

unread,
May 11, 2001, 6:38:26 PM5/11/01
to

dac <ac...@turdera.com.ar> wrote in message
news:9dho8u$ieenp$1...@ID-84876.news.dfncis.de...

Hi,

the result of the postfix ++ operator is the value of the operand before
the increment takes place. Your instruction effectively does
result = pointer
increment pointer
dereference result

If you want to increment the pointer and then dereference it you want
the prefix operator e.g. printf("%c", *(++p)); will give 'e' in your
example.

Personally I prefer to do this in two instructions to stop myself
getting confused.

HTH
Des Walker

Gergo Barany

unread,
May 11, 2001, 6:28:41 PM5/11/01
to
dac <ac...@turdera.com.ar> wrote:
> This is supposed to return the value pointed by p, and then increment p,
> right?
> My problem is that, looking at the precedence table, I can't seem to
> understand it.
> ++ has greater precedence than *, and both evaluate from right to left.
> So, in *p++ shouldn't ++ be evaluated first, and then dereferenced?

Ah, but it is. *p++ means the same as *(p++). The expression p++
evaluates to the "old" value of p, so that is what is dereferenced.
At some time before the next sequece point p is incremented, but
that doesn't affect the dereferencing operator, which conceptually
works with a copy of p's old value.

> Or the compiler "realizes" that being a postincrement, it has to be
> "executed" last?

The increment can take place at any time between the previous
sequence point and the next, but the postincrement expression
always evaluates to the value at the previous sequence point.

Gergo

--
Lost interest? It's so bad I've lost apathy.

Dave Vandervies

unread,
May 11, 2001, 6:32:33 PM5/11/01
to
In article <9dho8u$ieenp$1...@ID-84876.news.dfncis.de>,
dac <ac...@turdera.com.ar> wrote:
[Subject line: *p++]
(You should put your complete question in the body of your message,
since many people ignore or don't see the subject line when they're
reading or replying to your post.)

>This is supposed to return the value pointed by p, and then increment p,
>right?

Close enough. What it actually does is increment p and return the
value that p pointed to before the increment; there's no requirement on
the order that that happens in. (For example, some processors have an
instruction that dereferences a pointer and increments it at the same
time.)

>My problem is that, looking at the precedence table, I can't seem to
>understand it.
>++ has greater precedence than *, and both evaluate from right to left.
>So, in *p++ shouldn't ++ be evaluated first, and then dereferenced?

In most cases[1], precedence doesn't affect the order that things
happen, only the way the results are used.

Since ++ has higher precedence than *, *p++ gets parsed as *(p++) .
This does two things:
(p++)
means `Increment p and return the value that it had before it was
incremented', and
*foo
means `Evaluate foo and return what foo points at' (this requires that
foo evaluate to a pointer, which `p++' does if p is a pointer).
In this case `foo' is (p++), and evaluating it returns a pointer to
whatever p pointed at before it was incremented.
It often makes life easier to think of the dereferencing happening
before the increment, but there's no requirement that it actually
happen that way - it can happen at the same time, as noted above, and a
compiler can also generate code that increments the pointer and then
dereferences a saved copy of the old pointer.

In your example:

>char *p = "Hello";
>
>printf("%c", *p++);
>
>shouldn't return 'e' ?
>
>Or the compiler "realizes" that being a postincrement, it has to be
>"executed" last?

In this case, `p++' means `make p point at 'e', and return a pointer to
'H'', and dereferencing that pointer returns 'H'.
If you want a pointer to 'e', you can use *++p which means `increment
p, return the new value of p (that's the `++p' part), and then
dereference that pointer (which is what `*' does)'.


dave

[1] This means `I don't know of any exceptions, but if I claim there
aren't any somebody will come up with an example of one, and I've
already been wrong often enough today'.
--
Dave Vandervies dj3v...@student.math.uwaterloo.ca

You don't argue with the compiler writers (especially when they are right).
--Christian Bau in comp.lang.c

Dan Pop

unread,
May 11, 2001, 9:49:15 PM5/11/01
to
In <9dho8u$ieenp$1...@ID-84876.news.dfncis.de> "dac" <ac...@turdera.com.ar> writes:

>This is supposed to return the value pointed by p, and then increment p,
>right?

Right.

>My problem is that, looking at the precedence table, I can't seem to
>understand it.
>++ has greater precedence than *, and both evaluate from right to left.

Nope, they have equal precedence and right to left associativity.
It's the binary * operator (the multiplication operator) that has lower
precedence.

>So, in *p++ shouldn't ++ be evaluated first, and then dereferenced?

Correct.

>So, for example, having
>
>char *p = "Hello";
>
>printf("%c", *p++);
>
>shouldn't return 'e' ?

Nope. You need *++p for that.

>Or the compiler "realizes" that being a postincrement, it has to be
>"executed" last?

Nope. The post-increment operator, like any other operator, must yield
a value. The value it yields is the value of its operand. As a side
effect, it also increments its operand, but this does NOT affect the
value it yields. Likewise, the pre-increment operator yields the value
of its operand plus one. As a side effect, it also increments its
operand.

So, in *p++, the post-increment operator is evaluated first, it yields the
value of its argument and this value becomes the operand of the
dereferencing operator, which will yield 'H', even if p has been
incremented in the meantime.

A final point is that p needs not be incremented immediately, as part of
the evaluation of the pre/post-increment operator. This operation will
be performed at some moment between the evaluation of the operator and the
next sequence point (see the FAQ for a definition of "sequence point").

Dan
--
Dan Pop
CERN, IT Division
Email: Dan...@cern.ch
Mail: CERN - IT, Bat. 31 1-014, CH-1211 Geneve 23, Switzerland

dac

unread,
May 12, 2001, 12:03:47 AM5/12/01
to
> [Subject line: *p++]
> (You should put your complete question in the body of your message,
> since many people ignore or don't see the subject line when they're
> reading or replying to your post.)

You're right, mi fault, I didn't realized...
Thanks everybody for your answers, now I comprehend it correctly.

Lawrence Kirby

unread,
May 12, 2001, 12:06:17 PM5/12/01
to
In article <9di4qr$3e5$1...@sunnews.cern.ch> Dan...@cern.ch "Dan Pop" writes:

>In <9dho8u$ieenp$1...@ID-84876.news.dfncis.de> "dac" <ac...@turdera.com.ar> writes:
>
>>This is supposed to return the value pointed by p, and then increment p,
>>right?
>
>Right.
>
>>My problem is that, looking at the precedence table, I can't seem to
>>understand it.
>>++ has greater precedence than *, and both evaluate from right to left.
>
>Nope, they have equal precedence and right to left associativity.

That depends on what precedence table you happen to use. Saying that
postfix ++ and -- have higher precedence than the prefix unary operators
is equivalent to saying that the unary operators have equal precedence
and right associativity. If you look at the way expression syntax is
specified in the standard, postfix ++ and -- have in effect the same
precedence as . and -> i.e. higher than the the prefix unary operators.

>It's the binary * operator (the multiplication operator) that has lower
>precedence.

Whatever way you describe the precedence, postfix ++ binds more tightly
than both unary and binary *.

>>So, in *p++ shouldn't ++ be evaluated first, and then dereferenced?
>
>Correct.

As this demonstrates. :-)

--
-----------------------------------------
Lawrence Kirby | fr...@genesis.demon.co.uk
Wilts, England | 7073...@compuserve.com
-----------------------------------------

Steve Summit

unread,
May 12, 2001, 12:15:23 PM5/12/01
to
In article <9dho8u$ieenp$1...@ID-84876.news.dfncis.de>, dac evidently wrote:
> This is supposed to return the value pointed by p, and then increment p,
> right?

That's essentially correct.

> My problem is that, looking at the precedence table, I can't seem to
> understand it.
> ++ has greater precedence than *, and both evaluate from right to left.
> So, in *p++ shouldn't ++ be evaluated first, and then dereferenced?

I think what you've managed to do here is confuse precedence with
order of evaluation. But don't worry: it's extremely easy to
confuse precedence with order of evaluation, so easy that on the
other hand it can be very hard -- sometimes I find it essentially
impossible -- to explain why precedence is *not* the same thing
as order of evaluation. But your example, and more importantly,
your misinterpretation of this example, provides an excellent
arena for explaining this subtle point. So thanks for asking.

Yes, the precedence of postfix ++ is higher than unary *.
Now, the important thing about precedence is *not* that it tells
us what order things will be evaluated in. The important thing
about precedence is that it tells us which operators are matched
up with which operands.

When we look at the expression *p++, before we can even start
worrying about what order things will be evaluated in, we have
to figure out what the expression is supposed to *mean*. The *
says that we're taking the contents of a pointer, and the ++
says that we're incrementing something. But what are we
incrementing, the pointer or the value pointed to?

Precedence tells us. *If* the precedence of unary * were
higher than postfix ++ (which it is not), then *p++ would mean
"take the contents of the object pointed to by p, and increment
it in-place". However, since it's actually the precedence of
postfix ++ that's higher, the correct interpretation is that what
we're incrementing is the pointer, and what we're taking the
contents of is the pointer as operated on by the postfix ++
operator.

Notice that I did *not* say, "the interpretation is that first
we increment the pointer, and then we take the contents of
the incremented pointer". When we use words like "first" and
"and then", we're talking about order of evaluation, but order
of evaluation can be a very slippery thing to talk about. Here,
by talking about it too soon, we'd confuse ourselves into getting
the wrong answer, because as we'll see, although in *p++ we do in
fact take "the contents of the pointer as operated on by the
postfix ++ operator", by the definition of postfix ++, the
pointer value we'll take the contents of is the prior,
unincremented value.

So let's look at *p++ very carefully. Once more, since ++ has
higher precedence, we're (a) applying ++ to p, and (b) applying *
to the result. In other words, the correct interpretation is as
if we had written

*(p++)

So we're taking the contents of the subexpression p++. Now, what
is the value of the subexpression p++? The definition of postfix
++ is that it increments a variable, but yields as its value the
prior, unincremented value. Remember, when you say

int i = 5;
int j = i++;

you end up with the value 5 in j, even though i ends up as 6.
It's the same with pointer values: when you evaluate *p++, you
end up with the value that p used to point to, even though p ends
up pointing one beyond it. Try it -- compile and run this little
program:

#include <stdio.h>
int a[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int main()
{
int *p = &a[5];
int i = *p++;
printf("%d %d\n", i, *p);
return 0;
}

The program prints "5 6" -- i receives 5, the value p started out
pointing to, but p ends up pointing at 6.

Now, what if you don't want the value pointed to by the old value
of p, but the new one? That is, what if you want to increment
the pointer, and then take the value pointed to? This is now an
order of evaluation question, and it turns out that one of the
first things to think of whenever you have an order of evaluation
question is that there's a good chance that the answer does *not*
involve precedence.

We want an expression like *p++, in which a pointer is
incremented and its pointed-to value is fetched, except that
it's the new, incremented value that's fetched. One way, of
course, would be to do it as two separate statements: first
evaluate p = p + 1, then apply *p. But if we want to be Real C
Programmers and use the slick shortcut ++ operator, all we have
to do is remember that the distinction between using the old or
the new, the unincremented or the incremented value, is precisely
the distinction between the postfix and prefix forms of ++. So
to increment p and fetch the incremented value, we'd write *++p.

(Notice, by the way, that if the explanation of *p++ were
"first we increment the pointer, then we take the contents
of the incremented pointer" -- which, again, it is not --
then there would be no difference between *p++ and *++p.
But of course there is -- and should be -- a very significant
difference between these two, different expressions.)

While we're here, let's explain a few more things. Suppose we
were using *p++, and we noticed that it was the old value of the
pointer that was being used by the * operator, and we wanted it
to be the new value, and we said to ourselves, "I want it to first
increment the pointer, then take the contents of the incremented
pointer", and suppose further that we thought that the way to
get the order of evaluation we wanted was to use explicit
parentheses, leading us to write *(p++). What happens next?

Well, it doesn't work, of course. *(p++) acts precisely
like plain *p++, and the reason is that the real purpose of
parentheses is not to force an order of evaluation, but rather
to override the default precedence. So when you write *(p++),
all that the parentheses say is, "++ is applied to p, and * is
applied to the result", and that's the interpretation that the
higher precedence of ++ implied already, which is why the
parentheses don't make any difference. In other words, when
you've got an order of evaluation problem, not only is the
answer probably not going to involve precedence, it's probably
not going to involve parentheses, either.

What are parentheses good for, then? Well, let's go back to the
earlier question of whether *p++ increments the pointer or the
thing pointed to. We've seen that it increments the pointer,
but what if we want to increment the thing pointed to? That's a
precedence problem, so the appropriate answer *is*, "use explicit
parentheses", and the result is (*p)++. This says, * is applied
to p to fetch a value, and ++ is applied to the fetched value.

Exercise for the reader: (*p)++ increments the pointed-to value,
but (again, by the definition of postfix ++) returns the old,
unincremented pointed-to value. What if you wanted to increment
the pointed-to value and return the new, incremented, pointed-to
value? (Do you need explicit parentheses in this case?)

If I haven't put you to sleep by now, I'll launch into one more
little digression concerning the use of time-related concepts
to explain precedence. Ideally, to avoid confusion between
precedence and order of evaluation, we'd use time-related
language to explain only order of evaluation, not precedence.
But when your C teacher was first explaining precedence, the
explanation probably involved an expression along the lines of

1 + 2 * 3

and the statement was probably made that "the multiplication
happens first, before the addition, because multiplication
has higher precedence than addition". And having heard an
explanation like that, it's all too easy to come away with the
impression that precedence controls order of evaluation, and it's
also all too easy to get into trouble later when considering an
expression like *p++, where the precedence does *not* control,
doesn't even come close to controlling, the aspect of evaluation
order that you're interested in.

If we look at the expression 1 + 2 * 3 very carefully, the
key aspect explained by precedence is that the multiplication
operator is applied to the operands 2 and 3, and the addition
operator is applied to 1 and the result of the multiplication.
(Notice that I said "and", not "and then"). Here, although
there's definitely an order of evaluation issue, and although the
order of evaluation is apparently influenced by the precedence
somehow, the influence is actually not a direct one. The real
constraint on the order of evaluation is that we obviously
can't complete an addition which involves the result of the
multiplication until we've got the result of that multiplication.
So we're probably going to have to do the multiplication first
and the addition second, but this is mostly a consequence of
causality, not precedence.

But if your C instructor misled you into thinking that precedence
had more to do with order of evaluation than it does, have pity,
because I don't know of a good way of explaining precedence that
doesn't involve time-related concepts, either. My students used
to have to watch me do battle with myself, lips flapping like a
fish but with no words coming out, as one part of my brain,
paranoid about the possibility of later misunderstandings,
desperately tried to keep another part from blurting out the
dreaded "the multiplication happens first, before the addition,
because multiplication has higher precedence than addition".
(And at least half the time, that's probably what I ended up
saying anyway.)


> So, for example, having
> char *p = "Hello";
> printf("%c", *p++);
> shouldn't return 'e' ?

Nope. By the arguments above, it prints 'H'.
To print 'e', you'd want *++p.

See also the comp.lang.c FAQ list, question 4.3.
See also http://www.eskimo.com/~scs/readings/precvsooe.960725.html .

Steve Summit
s...@eskimo.com

8889185069805239596085360662344508517964037796278267072470951552302

Dan Pop

unread,
May 12, 2001, 3:13:01 PM5/12/01
to

>In article <9di4qr$3e5$1...@sunnews.cern.ch> Dan...@cern.ch "Dan Pop" writes:
>
>>In <9dho8u$ieenp$1...@ID-84876.news.dfncis.de> "dac" <ac...@turdera.com.ar> writes:
>>
>>>This is supposed to return the value pointed by p, and then increment p,
>>>right?
>>
>>Right.
>>
>>>My problem is that, looking at the precedence table, I can't seem to
>>>understand it.
>>>++ has greater precedence than *, and both evaluate from right to left.
>>
>>Nope, they have equal precedence and right to left associativity.
>
>That depends on what precedence table you happen to use.

The one from K&R2.

>>It's the binary * operator (the multiplication operator) that has lower
>>precedence.
>
>Whatever way you describe the precedence, postfix ++ binds more tightly
>than both unary and binary *.

A statement that doesn't apply to the the prefix ++, so I find it less
useful than the K&R2 operator precedence/associativity table, which, with
the same line, covers quite a bunch of operators, including postfix and
prefix ++.

pete

unread,
May 12, 2001, 5:08:59 PM5/12/01
to
Steve Summit wrote:

> Yes, the precedence of postfix ++ is higher than unary *.

Table 2-1 from K&R2, shows ++ and unary * on the same line.
The text on the preceding page says
"Operators on the same line have the same precedence; "

Besides precedence and order of evaluation, there is also
something called "associativity".
Most operators associate from left to right but,
++ and unary *, associate from right to left.
Associativity breaks ties in precedence.

--
pete

Kaz Kylheku

unread,
May 12, 2001, 5:32:44 PM5/12/01
to
On Sat, 12 May 2001 17:08:59 -0400, pete <pfi...@mindspring.com> wrote:
>Steve Summit wrote:
>
>> Yes, the precedence of postfix ++ is higher than unary *.
>
>Table 2-1 from K&R2, shows ++ and unary * on the same line.
>The text on the preceding page says
>"Operators on the same line have the same precedence; "
>
>Besides precedence and order of evaluation, there is also
>something called "associativity".
>Most operators associate from left to right but,
>++ and unary *, associate from right to left.

You mean *unary* ++ and unary *. Note that Steve is talking about
*postfix* ++.

>Associativity breaks ties in precedence.

In the case of multiple unary operators applied in sequence, like -*++p, the
right-to-left associativity tells you that it means -(*(++p)) rather than
((-*)++)p. But is that surprising, given that it doesn't make sense to apply
one operator to another? :)

On the other hand, note that the *postfix* ++ is not on the same level of
precedence as the unary *! It's not associativity which untangles
*p++, but straight precedence: postfix expressions have a higher precedence
than unary, hence *(p++).

Also note that K&R2 doesn't define the C language, the standard does.
The standard does not use the concept of associativity precedence at all.
Rather the grammar it presents shows associativity through the appropriate
left or right recursion, and precedence is established implicitly using a
hierarchy of grammar productions.

pete

unread,
May 12, 2001, 5:46:45 PM5/12/01
to
Kaz Kylheku wrote:
>
> Also note that K&R2 doesn't define the C language, the standard does.
> The standard does not use the concept of associativity precedence at all.
> Rather the grammar it presents shows associativity through the appropriate
> left or right recursion, and precedence is established implicitly using a
> hierarchy of grammar productions.

I didn't realize how much difference there was between
K&R2's description of C, and the standard, thank you.

--
pete

Dave Vandervies

unread,
May 12, 2001, 6:33:40 PM5/12/01
to
In article <9djnir$gcb$1...@eskinews.eskimo.com>,
Steve Summit <s...@eskimo.com> wrote:

> My students used
>to have to watch me do battle with myself, lips flapping like a
>fish but with no words coming out, as one part of my brain,
>paranoid about the possibility of later misunderstandings,
>desperately tried to keep another part from blurting out the
>dreaded "the multiplication happens first, before the addition,
>because multiplication has higher precedence than addition".
>(And at least half the time, that's probably what I ended up
>saying anyway.)

Wouldn't `the multiplication has higher precedence; in this case it
happens first because of that, but in other cases that's not so simple'
(possibly followed by a brief example of a case where it's not so
simple (such as *p++)) work?


dave

--
Dave Vandervies dj3v...@student.math.uwaterloo.ca
I think you need a scanf expert to check out your program. I've only been
doing C for about eleven and a half years, so IMHO I'm not really ready
for scanf yet. --Richard Heathfield in comp.lang.c

Micah Cowan

unread,
May 12, 2001, 8:12:39 PM5/12/01
to
Dan...@cern.ch (Dan Pop) writes:

> >>>++ has greater precedence than *, and both evaluate from right to left.
> >>
> >>Nope, they have equal precedence and right to left associativity.
> >
> >That depends on what precedence table you happen to use.
>
> The one from K&R2.

Funny - I use the one dictated by the Standard (which, IIUC, is the
only authoritative source), which states that postfix ++ is higher
precedence than *. Not that it really matters, since either way of
looking at it produces the same results

Micah

--
He who rebukes a scoffer gets shame for himself.
Proverbs 9:7

Dan Pop

unread,
May 12, 2001, 9:23:30 PM5/12/01
to

>Dan...@cern.ch (Dan Pop) writes:
>
>> >>>++ has greater precedence than *, and both evaluate from right to left.
>> >>
>> >>Nope, they have equal precedence and right to left associativity.
>> >
>> >That depends on what precedence table you happen to use.
>>
>> The one from K&R2.
>
>Funny - I use the one dictated by the Standard

How does the precedence table dictated by the standard look like?

>(which, IIUC, is the
>only authoritative source), which states that postfix ++ is higher
>precedence than *. Not that it really matters, since either way of
>looking at it produces the same results

Which is hardly surprinsing, considering that what the standard did was
to codify the precedence/associativity table from K&R1 using a different
formalism. Considering the equivalence of the two methods, I prefer the
table, which is compact and easy to understand and use (I keep it under
my keyboard :-)

dac

unread,
May 12, 2001, 10:20:59 PM5/12/01
to
> See also the comp.lang.c FAQ list, question 4.3.
> See also http://www.eskimo.com/~scs/readings/precvsooe.960725.html .
>
> Steve Summit
> s...@eskimo.com
>

Impossible not to understand such a wonderful explanation! :-)
Thanks a lot for taking the time to write such a message.
(BTW I've read all the articles available at your page, they're just great.)

Greetings,
David.

Micah Cowan

unread,
May 12, 2001, 10:58:55 PM5/12/01
to
Dan...@cern.ch (Dan Pop) writes:

> How does the precedence table dictated by the standard look like?

Why, remarkably like a subsection of the bookmarks panel in my PDF
version of the standard, of course! :)

For yourself, I guess you'd have to make a seperate list of the
subclauses of C99 6.5, or the equivalent C89 subclauses. I can see
why you favor the K&R table... ;)

> Considering the equivalence of the two methods, I prefer the
> table, which is compact and easy to understand and use (I keep it under
> my keyboard :-)

But only for the purposes of reading others' code (or writing
obfuscated entries) I hope... I'm a strong believer in the philosophy
that parens demarcate precedence far more legibly than precedence
tables.

Micah

--
Wise people store up knowledge, but the mouth of the
foolish is near destruction.
Proverbs 10:14

Kaz Kylheku

unread,
May 13, 2001, 12:28:00 AM5/13/01
to
On 12 May 2001 22:33:40 GMT, Dave Vandervies

<dj3v...@student.math.uwaterloo.ca> wrote:
>In article <9djnir$gcb$1...@eskinews.eskimo.com>,
>Steve Summit <s...@eskimo.com> wrote:
>
>> My students used
>>to have to watch me do battle with myself, lips flapping like a
>>fish but with no words coming out, as one part of my brain,
>>paranoid about the possibility of later misunderstandings,
>>desperately tried to keep another part from blurting out the
>>dreaded "the multiplication happens first, before the addition,
>>because multiplication has higher precedence than addition".
>>(And at least half the time, that's probably what I ended up
>>saying anyway.)
>
>Wouldn't `the multiplication has higher precedence; in this case it
>happens first because of that, but in other cases that's not so simple'
>(possibly followed by a brief example of a case where it's not so
>simple (such as *p++)) work?

Sometimes you have to lie, because otherwise you will swamp the the students
with too many pieces of information all at once.

Since multiplication is not a side effect, it does actually happen before the
addition. It cannot be delayed because the addition has an operand which is
produced by the multiplication.

Of course, the order in which the free operands are fetched is unspecified, but
that can be deferred to a later lecture, as can discussions about expressions
that perform side effects.

Perhaps a better way to say it whilst avoiding too much confusion might be that
the precedence establishes multiplication as subordinate to the addition (pause
to draw a little syntax tree). The addition depends on the result of the
multiplication, and this dependency causes the multiplication to be done first.

This version avoids saying that precedence causes something to be done first.
However, the students are probably going to be oblivious to the subtlety of
this until they are introduced to issues of evaluation order.

Dan Pop

unread,
May 13, 2001, 12:22:23 AM5/13/01
to

>Dan...@cern.ch (Dan Pop) writes:
>
>> Considering the equivalence of the two methods, I prefer the
>> table, which is compact and easy to understand and use (I keep it under
>> my keyboard :-)
>
>But only for the purposes of reading others' code (or writing
>obfuscated entries) I hope...

Indeed. I don't bother writing obfuscated code, so it's exclusively for
reading other people's code.

>I'm a strong believer in the philosophy
>that parens demarcate precedence far more legibly than precedence
>tables.

Me too. However, parenthesis abuse can impair readability, too, so they
should be used carefully. Three levels of nesting is already too much,
breaking the expression into simpler temporary subexpressions should be
considered as an alternative.

Richard Heathfield

unread,
May 13, 2001, 7:17:08 AM5/13/01
to

Kaz is of course correct, but you may have picked up the wrong
impression. "Precedence" is a descriptive tool which K&R use to explain
how expressions are evaluated. The Standard doesn't mention precedence
at all, but that doesn't invalidate K&R's explanation one iota. As long
as C works "as if" K&R's precedence descriptions were correct, then
those descriptions will continue to be correct.

K&R2 can still be considered to be a highly authoritative guide to ANSI
C (1989), second only to the Standard itself (which is definitive).

--
Richard Heathfield : bin...@eton.powernet.co.uk
"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
K&R answers, C books, etc: http://users.powernet.co.uk/eton

Richard Heathfield

unread,
May 13, 2001, 7:19:52 AM5/13/01
to
Micah Cowan wrote:
>
> Dan...@cern.ch (Dan Pop) writes:
>
> > >>>++ has greater precedence than *, and both evaluate from right to left.
> > >>
> > >>Nope, they have equal precedence and right to left associativity.
> > >
> > >That depends on what precedence table you happen to use.
> >
> > The one from K&R2.
>
> Funny - I use the one dictated by the Standard (which, IIUC, is the
> only authoritative source), which states that postfix ++ is higher
> precedence than *.

<grin> Do you have a citation for that statement, or a reference for the
precedence table in the Standard?

> Not that it really matters, since either way of
> looking at it produces the same results

Yes, I think this is the key point.

Ben Pfaff

unread,
May 13, 2001, 10:38:27 AM5/13/01
to
Richard Heathfield <bin...@eton.powernet.co.uk> writes:

> Micah Cowan wrote:
> >
> > Dan...@cern.ch (Dan Pop) writes:
> >
> > > >That depends on what precedence table you happen to use.
> > >
> > > The one from K&R2.
> >
> > Funny - I use the one dictated by the Standard (which, IIUC, is the
> > only authoritative source), which states that postfix ++ is higher
> > precedence than *.
>
> <grin> Do you have a citation for that statement, or a reference for the
> precedence table in the Standard?

Not the precedence table *in* the Standard (there is none) but
the one *dictated by* the Standard--which just happens to be the
same one as in K&R2 (modulo any mistakes).

Lawrence Kirby

unread,
May 13, 2001, 3:33:45 PM5/13/01
to
In article <9dk1vt$rle$1...@sunnews.cern.ch> Dan...@cern.ch "Dan Pop" writes:

...

>>>>My problem is that, looking at the precedence table, I can't seem to
>>>>understand it.
>>>>++ has greater precedence than *, and both evaluate from right to left.
>>>
>>>Nope, they have equal precedence and right to left associativity.
>>
>>That depends on what precedence table you happen to use.
>
>The one from K&R2.

No doubt, but that is just one possible example. My point is that
saying that ++ has higher precedence than (unary or binary) * is
perfectly valid.

>>>It's the binary * operator (the multiplication operator) that has lower
>>>precedence.
>>
>>Whatever way you describe the precedence, postfix ++ binds more tightly
>>than both unary and binary *.
>
>A statement that doesn't apply to the the prefix ++,

Because the situation never arises. Prefix unary operators can never
compete for the same operand because only one of them can be adjacent
to it.

>so I find it less
>useful than the K&R2 operator precedence/associativity table, which, with
>the same line, covers quite a bunch of operators, including postfix and
>prefix ++.

I agree that it is a simple way of expressing the syntax. But that doesn't
mean that other ways are wrong. In your "Nope" statement above you
are simply expressing your own preferred form of precedence table, not any
fundamental truth.

Lawrence Kirby

unread,
May 13, 2001, 2:53:46 PM5/13/01
to
In article <3AFE6DD8...@eton.powernet.co.uk>
bin...@eton.powernet.co.uk "Richard Heathfield" writes:

>Micah Cowan wrote:
>>
>> Dan...@cern.ch (Dan Pop) writes:
>>
>> > >>>++ has greater precedence than *, and both evaluate from right to left.
>> > >>
>> > >>Nope, they have equal precedence and right to left associativity.
>> > >
>> > >That depends on what precedence table you happen to use.
>> >
>> > The one from K&R2.
>>
>> Funny - I use the one dictated by the Standard (which, IIUC, is the
>> only authoritative source), which states that postfix ++ is higher
>> precedence than *.
>
><grin> Do you have a citation for that statement, or a reference for the
>precedence table in the Standard?

See footnote 35 in C90 or footnote 71 in C99.

"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."

For C90 this gives a "standard" 17 level precedence table:

1. () parenthesized expression (which can be viewed as an operator whose
result including lvalueness is the same as its operand).

2. [] . ->
() function call operator
++ postfix operator
-- postfix operator

3. & * + - ~ ! unary operators
++ prefix operator
-- prefix operator
sizeof

4. () cast operator

5. * / % binary operators

6. + - binary operators

7. << >>

8. < > <= >=

9. == !=

10. & binary operator

11. ^

12. |

13. &&

14. ||

15. ?: conditional operator

16. = *= /= %= += -= <<= >>= &= ^= |=

17 , comma operator

>> Not that it really matters, since either way of
>> looking at it produces the same results
>
>Yes, I think this is the key point.

In truth prcedence tables don't tell the whole story about C's expression
syntax. The syntax rules disallow certain combinations that precedence
tables don't cover. An obvious example is that the token following the
the . or -> operators can only be an identifier.

Richard Heathfield

unread,
May 14, 2001, 12:59:56 AM5/14/01
to
Lawrence Kirby wrote:
>
> In article <3AFE6DD8...@eton.powernet.co.uk>
> bin...@eton.powernet.co.uk "Richard Heathfield" writes:
>
> >Micah Cowan wrote:
> >>
> >> Dan...@cern.ch (Dan Pop) writes:
> >>
> >> > >>>++ has greater precedence than *, and both evaluate from right to left.
> >> > >>
> >> > >>Nope, they have equal precedence and right to left associativity.
> >> > >
> >> > >That depends on what precedence table you happen to use.
> >> >
> >> > The one from K&R2.
> >>
> >> Funny - I use the one dictated by the Standard (which, IIUC, is the
> >> only authoritative source), which states that postfix ++ is higher
> >> precedence than *.
> >
> ><grin> Do you have a citation for that statement, or a reference for the
> >precedence table in the Standard?
>
> See footnote 35 in C90 or footnote 71 in C99.
>
> "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."

Yes. I hadn't noticed that, but I had noticed the absence of a
precedence table in the Standard. (Either that, or I have completely
overlooked its presence!)

>
> For C90 this gives a "standard" 17 level precedence table:

In that case it appears that my extrapolation back to C90 was erroneous,
so I guess I owe Micah Cowan an apology.

ke...@hplb.hpl.hp.com

unread,
May 14, 2001, 4:59:49 AM5/14/01
to
In article <9dho8u$ieenp$1...@id-84876.news.dfncis.de>,

"dac" <ac...@turdera.com.ar> writes:
> This is supposed to return the value pointed by p, and then increment p,
> right?
> My problem is that, looking at the precedence table, I can't seem to
> understand it.
> ++ has greater precedence than *, and both evaluate from right to left.
> So, in *p++ shouldn't ++ be evaluated first, and then dereferenced?

Yes. It is.

> So, for example, having
>
> char *p = "Hello";
>
> printf("%c", *p++);
>
> shouldn't return 'e' ?

No, 'H'.

> Or the compiler "realizes" that being a postincrement, it has to be
> "executed" last?

It can be executed whenever the compiler thinks fit. However, the
* must use the *old* value of `p`, because that's what postfix ++
does: in E++, the *value* of the expression is the value at the location
E, *and* E will be incremented "later".

(The latest "later" is well-defined and called a "sequence point". The
typical sequence point is end-of-statment, which you can usefully
think of as the associated ";".)

--
Chris "... && || ?: if() while() f(A) ..." Dollin
C FAQs at: http://www.faqs.org/faqs/by-newsgroup/comp/comp.lang.c.html

Dan Pop

unread,
May 14, 2001, 3:00:17 PM5/14/01
to

>In article <9dk1vt$rle$1...@sunnews.cern.ch> Dan...@cern.ch "Dan Pop" writes:
>
>...
>
>>>>>My problem is that, looking at the precedence table, I can't seem to
>>>>>understand it.
>>>>>++ has greater precedence than *, and both evaluate from right to left.
>>>>
>>>>Nope, they have equal precedence and right to left associativity.
>>>
>>>That depends on what precedence table you happen to use.
>>
>>The one from K&R2.
>
>No doubt, but that is just one possible example. My point is that
>saying that ++ has higher precedence than (unary or binary) * is
>perfectly valid.
>
>>>>It's the binary * operator (the multiplication operator) that has lower
>>>>precedence.
>>>
>>>Whatever way you describe the precedence, postfix ++ binds more tightly
>>>than both unary and binary *.
>>
>>A statement that doesn't apply to the the prefix ++,
>
>Because the situation never arises. Prefix unary operators can never
>compete for the same operand because only one of them can be adjacent
>to it.

If you remove "postfix" from your statement it *could* be interpreted
as saying that, in the expression ++*p, the ++ operator binding tighter
than *, it is parsed as *(++p). This was my point.

>>so I find it less
>>useful than the K&R2 operator precedence/associativity table, which, with
>>the same line, covers quite a bunch of operators, including postfix and
>>prefix ++.
>
>I agree that it is a simple way of expressing the syntax. But that doesn't
>mean that other ways are wrong. In your "Nope" statement above you
>are simply expressing your own preferred form of precedence table, not any
>fundamental truth.

In my "Nope" statement above I was referring to the fact that the OP was
looking at the "wrong" * operator in the precedence table. I am not aware
of *any* *explicit* C operator precedence table where ++ and unary * have
different precedences.

Chris Torek

unread,
May 18, 2001, 5:19:32 PM5/18/01
to
>>In article <9djnir$gcb$1...@eskinews.eskimo.com>,
>>Steve Summit <s...@eskimo.com> wrote:
>>>... My students used

>>>to have to watch me do battle with myself, lips flapping like a
>>>fish but with no words coming out, as one part of my brain,
>>>paranoid about the possibility of later misunderstandings,
>>>desperately tried to keep another part from blurting out the
>>>dreaded "the multiplication happens first, before the addition,
>>>because multiplication has higher precedence than addition".
>>>(And at least half the time, that's probably what I ended up
>>>saying anyway.)

>On 12 May 2001 22:33:40 GMT, Dave Vandervies


><dj3v...@student.math.uwaterloo.ca> wrote:
>>Wouldn't `the multiplication has higher precedence; in this case it
>>happens first because of that, but in other cases that's not so simple'
>>(possibly followed by a brief example of a case where it's not so
>>simple (such as *p++)) work?

In article <slrn9frv...@cafe.net>


Kaz Kylheku <k...@ashi.footprints.net> writes:
>Sometimes you have to lie, because otherwise you will swamp the the students
>with too many pieces of information all at once.

I prefer not to lie, and in many cases I think there are ways to
accomplish both goals: giving students information in small pieces,
yet not lying either. :-) In cases where it is (or at least appears)
impossible, I think it is worth telling them that this is a "white
lie" and the details, and flaws, will be exposed later.

Here, I think the trick is to establish the idea of "order of
evalution" first. This is easy to do even in places where the
concepts of "precedence and associativy" never occur:

printf("%d\n", f() + g() + h());

along with:

int f(void) { puts("f"); return 1; }
int g(void) { puts("g"); return 2; }
int h(void) { puts("h"); return 3; }

This code fragment can print "f", "g", and "h" in any order, followed
by the number 6. No matter what order f(), g(), and h() are called,
the sum is always six. If you *want* "g" to come out first, then "f",
then "h", you must break up the expression to get the desired order
of evalution:

int fval, gval, hval;

gval = g(); /* make sure we call g() first */
fval = f(); /* and f() second */
hval = h(); /* and h() third */
printf("%d\n", fval + gval + hval);

Once the students understand this, *then* you give them an expression
like:

fval * gval + hval

and describe the process of binding the operators to the operands.
Clearly the result is different if the binding is strictly left to
right, or uses the grade-school "my dear aunt sally" (Mult Div Add
Subtract) rule:

(fval * gval) + hval

or, as in APL, simply runs strictly from right to left:

fval * (gval + hval)

Since these give *different* answers, a language has to pick out
some set of rules for what to do with un-parenthesized expressions.

Then, given that the students understand the idea of binding simple
binary operators like "+" and "*", and the idea of actual order of
evaluation, you move on to a third example:

printf("%d\n", f() * g() + h());

where f(), g(), and h() continue to announce their actual order
of evaluation.

At this point, you simply remark that the compiler is free to
pretend you wrote:

saved_hval = h();
saved_fval = f();
saved_gval = g();
printf("%d\n", saved_fval * saved_gval + saved_hval);

and that nothing you can do with parentheses can change this!

This effectively "uncouples" the low-level "order of evaluation"
-- now a well-defined concept -- from the "parse tree binding".

At that point, you simply need to repeat, occasionally, that
"precedence, although it contains the word `precede', does not
necessarily force one thing to precede another" -- and give out
exercises in which the students are required to answer whether some
f() has to get called, and print its "f" output, before some g()
or h().

>Perhaps a better way to say it whilst avoiding too much confusion might
>be that the precedence establishes multiplication as subordinate to the
>addition (pause to draw a little syntax tree).

I think drawing parse trees is also quite helpful. You can then
say that the point of precedence and associativity is merely for
us humans to draw the proper tree, and point out that the ANSI C
standards do not use explicit precedence and associativity. Instead,
the C standards use a long, drawn-out grammar that is very tedious
to work with -- if the students are supposed to learn grammars,
this is a good time to have them do exercises to see just *how*
tedious -- and that we humans prefer to dispose of this nonsense
using "prec&assoc" shortcuts that give the same answer, but are
just stuff *we* use, not things the *computer* uses.

By emphasizing that "P&A" are "purely for human consumption", as it
were, you can help keep "order of evaluation" separate. This "OoE"
happens whether we want it or not, but "P&A" is just a fiction we
use to keep things straight for ourselves, so the two are inherently
different.
--
In-Real-Life: Chris Torek, Wind River Systems
El Cerrito, CA, USA Domain: to...@bsdi.com +1 510 234 3167
http://claw.bsdi.com/torek/ (not always up) I report spam to abuse@.

CBFalconer

unread,
May 18, 2001, 10:32:26 PM5/18/01
to
Chris Torek wrote:
>
... snip ...

>
> Then, given that the students understand the idea of binding simple
> binary operators like "+" and "*", and the idea of actual order of
> evaluation, you move on to a third example:
>
> printf("%d\n", f() * g() + h());
>
> where f(), g(), and h() continue to announce their actual order
> of evaluation.
>
> At this point, you simply remark that the compiler is free to
> pretend you wrote:
>
> saved_hval = h();
> saved_fval = f();
> saved_gval = g();
> printf("%d\n", saved_fval * saved_gval + saved_hval);
>
> and that nothing you can do with parentheses can change this!

I think you meant something slightly different. Counter-example:

printf("%d\n", f() * ( g() + h() ));

--
Chuck F (cbfal...@my-deja.com) (cbfal...@XXXXworldnet.att.net)
http://www.qwikpages.com/backstreets/cbfalconer :=(down for now)
(Remove "NOSPAM." from reply address. my-deja works unmodified)
mailto:u...@ftc.gov (for spambots to harvest)


Kaz Kylheku

unread,
May 18, 2001, 10:57:40 PM5/18/01
to
On Sat, 19 May 2001 02:32:26 GMT, CBFalconer <cbfal...@my-deja.com> wrote:
>Chris Torek wrote:
>> At this point, you simply remark that the compiler is free to
>> pretend you wrote:
>>
>> saved_hval = h();
>> saved_fval = f();
>> saved_gval = g();
>> printf("%d\n", saved_fval * saved_gval + saved_hval);
>>
>> and that nothing you can do with parentheses can change this!
>
>I think you meant something slightly different. Counter-example:
>
> printf("%d\n", f() * ( g() + h() ));

I think the students will ultimately have to play with various combinations.
Whether any combination is a counterexample depends on the evaluation order
chosen by the compiler. If by chance g() and h() are called first, it supports
the incorrect hypothesis without denying the correct model. So an alternate
combination must be sought. It could well be that the given compiler always
confirms the naive intuition, and so the students will have to seek another
one to vindicate the teacher. ;)

Chris Torek

unread,
May 19, 2001, 2:36:13 AM5/19/01
to
>Chris Torek wrote:
>> Then, given that the students understand the idea of binding simple
>> binary operators like "+" and "*", and the idea of actual order of
>> evaluation, you move on to a third example:
>>
>> printf("%d\n", f() * g() + h());
>>
>> where f(), g(), and h() continue to announce their actual order
>> of evaluation.
>>
>> At this point, you simply remark that the compiler is free to
>> pretend you wrote:
>>
>> saved_hval = h();
>> saved_fval = f();
>> saved_gval = g();
>> printf("%d\n", saved_fval * saved_gval + saved_hval);
>>
>> and that nothing you can do with parentheses can change this!

[There is a problem in the phrasing here: the last word, "this",
refers to "the order in which the three functions are called".]

In article <3B05D9C4...@my-deja.com>


CBFalconer <cbfal...@worldnet.att.net> writes:
>I think you meant something slightly different. Counter-example:
>
> printf("%d\n", f() * ( g() + h() ));

This can still call h() first, then f(), then g():

saved_hval = h();
saved_fval = f();
saved_gval = g();

printf("%d\n", saved_fval * (saved_gval + saved_hval));

I suspect you read "this" as meaning "the numeric result" rather
than "the order in which the three functions are called": yes,
parentheses influence the numeric result.

0 new messages