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

pointer/post-increment inconsistency???

3 views
Skip to first unread message

William R. Pearson

unread,
Mar 17, 2001, 9:04:24 AM3/17/01
to

I recently received this email, and, not being a C++ programmer, was
surprised that there might be an inconsistency:

================

I'm seeing the "*X++ = Y;" idiom a lot in the code
and its causing me some problems. According to K&R the ++ (both
prefix and postfix) operators have the same precedence as * and those
operators are evaluated right to left. So "*X = Y; X++;" would be
equivalent code. Fair enough, BUT Stroustrup says postfix ++ has
higher precedence than prefix ++ and * (which have equivalent
precedence). This means that "*X++ = Y;" would be rewritten as "X++;
*X = Y;".

Should I assume that "*X = Y; X++;" is what is desired?

================

I think there is no question that *x++ = y; means *x = y; x++; in 'C'.

Is there a difference in 'C++'?

Bill Pearson

Clark S. Cox, III

unread,
Mar 17, 2001, 9:32:47 AM3/17/01
to
William R. Pearson <w...@alpha0.bioch.virginia.edu> wrote:

> I recently received this email, and, not being a C++ programmer, was
> surprised that there might be an inconsistency:
>
> ================
>
> I'm seeing the "*X++ = Y;" idiom a lot in the code
> and its causing me some problems. According to K&R the ++ (both
> prefix and postfix) operators have the same precedence as * and those
> operators are evaluated right to left. So "*X = Y; X++;" would be
> equivalent code. Fair enough, BUT Stroustrup says postfix ++ has
> higher precedence than prefix ++ and * (which have equivalent
> precedence). This means that "*X++ = Y;" would be rewritten as "X++;
> *X = Y;".

No it doesn't. it means that it could be rewritten as:

*(X++) = Y;

> Should I assume that "*X = Y; X++;" is what is desired?
>
> ================
>
> I think there is no question that *x++ = y; means *x = y; x++; in 'C'.
>
> Is there a difference in 'C++'?

No, just because the operator has higher precidence, doesn't mean
that it's side effects will take effect earlier.


--
http://www.whereismyhead.com/clark/
Clark S. Cox, III
clar...@yahoo.com

Grzegorz Sakrejda

unread,
Mar 17, 2001, 1:45:32 PM3/17/01
to
w...@alpha0.bioch.virginia.edu (William R. Pearson) wrote in
<kj4rwspk...@alpha0.bioch.virginia.edu>:

postfix ++ operator returns temporary variable initialized with
pre incremented value of X.

So *X++ = Y is fine.

*X++=X is undefined behaviour because X value here
is modified twice between to sequence points.
When postfix operator ++ increments value of it's argument - is
not defined, but it must be before next sequence point.
Beause of this also accessing value of X before next seq point
will yield undefined behaviour.

grzegorz

Clark S. Cox, III

unread,
Mar 17, 2001, 1:54:54 PM3/17/01
to
Grzegorz Sakrejda <gsak...@yahoo.com> wrote:

> w...@alpha0.bioch.virginia.edu (William R. Pearson) wrote in
> <kj4rwspk...@alpha0.bioch.virginia.edu>:
>
> >
> >I recently received this email, and, not being a C++ programmer, was
> >surprised that there might be an inconsistency:
> >
> >================
> >
> >I'm seeing the "*X++ = Y;" idiom a lot in the code
> >and its causing me some problems. According to K&R the ++ (both
> >prefix and postfix) operators have the same precedence as * and those
> >operators are evaluated right to left. So "*X = Y; X++;" would be
> >equivalent code. Fair enough, BUT Stroustrup says postfix ++ has
> >higher precedence than prefix ++ and * (which have equivalent
> >precedence). This means that "*X++ = Y;" would be rewritten as "X++;
> >*X = Y;".
> >
> >Should I assume that "*X = Y; X++;" is what is desired?
> >
> >================
> >
> >I think there is no question that *x++ = y; means *x = y; x++; in 'C'.
> >
> >Is there a difference in 'C++'?
> >
> >Bill Pearson
>
> postfix ++ operator returns temporary variable initialized with
> pre incremented value of X.
>
> So *X++ = Y is fine.
>
> *X++=X is undefined behaviour because X value here
> is modified twice between to sequence points.

It's only modified once.

> When postfix operator ++ increments value of it's argument - is
> not defined, but it must be before next sequence point.
> Beause of this also accessing value of X before next seq point
> will yield undefined behaviour.

This is why *X++=X is undefined, not the other reason you listed.

Chris Torek

unread,
Mar 17, 2001, 3:59:30 PM3/17/01
to
In article <kj4rwspk...@alpha0.bioch.virginia.edu>

William R. Pearson <w...@alpha0.bioch.virginia.edu> writes:
>I recently received this email, and, not being a C++ programmer, was
>surprised that there might be an inconsistency:

[There is and is not, depending on how you want to look at it; C++
is not C, and the languages differ substantially, especially when
using things like operator overloading in C++. That said, on to the
email:]

>================
>I'm seeing the "*X++ = Y;" idiom a lot in the code
>and its causing me some problems. According to K&R the ++ (both
>prefix and postfix) operators have the same precedence as * and those

>operators are evaluated right to left. ...

There is a terminology problem coming up here. I have seen this
many times before. It happens because people see the words
"precedence" and think: "Ah, I know the computer does everything
sequentially. Precedence must therefore determine the sequential
order. This is obviously right; after all, to say `spring precedes
summer' means that spring must happen *first*."

Unfortunately, while it is "obviously right", it is actually wrong.

In C and C++, and indeed in almost any modern language, the task
of taking a piece of source code and assigning some meaning to it
is broken up into a number of phases. One of these phases is called
"parsing", and it consists of extracting "tokens" and building a
"parse tree".

For mathematical expressions in particular, it is especially
convenient for humans to talk about a parse tree in terms of
"precedence" and "associativity". These are terms we all learned
in our early schooling (even if some later forgot them :-) ). For
instance, multiplication and division "happen before" addition and
subtraction, because they are "higher precedence", so that:
3 + 4 * 5
does not mean:
(3 + 4) * 5
but rather:
3 + (4 * 5).

Now, indeed, "everyone knows" that this is what is meant -- but
how are we going to tell a *computer* that this is what is meant?
Computers are basically very fast idiots, so we have to come up
with some simple and definite set of rules. In computer science
parsing theory, there are any number of rules we can use, including
-- but not limited to -- concepts of "precedence and associativity".

Using these is good, in a way, because it means that the computer's
interpretation of any expression is likely to match the human's.
If you can tell the machine "multiplication is higher precedence
than addition, and division and subtraction are left-associative",
then you can be sure that it will see:
a + b * c / d / e
as "meaning":
a + (((b * c) / d) / e)
and not something bizarre like:
((a + b) * (c / d)) / e
Unfortunately, this is also bad in a way, because the word "precedence"
sounds just like the word "precede", and sets up an additional false
interpretation in the mind of the human. (Of course, in languages
other than C and C++, perhaps the syntax and semantics could be
constructed such that "precedence" really *does* have this meaning,
and then one could argue that it is wholly good.)

Anyway, after passing through a parser, what you get out of these
"operator precedence" grammars is an expression "tree" that looks
something like this:

+
/ \
3 * (represents 3 + 4 * 5)
/ \
4 5

A C or C++ compiler is then free to produce any machine code
that comes up with the "right answer", regardless of the order
of calls. Replacing 3, 4, and 5 with a(), b(), and c():

+
/ \
a() * (represents a() + b() * c())
/ \
b() c()

and having each function print its name on a line by itself (e.g.,
puts("a()") in a(), and the like), and running a program containing
this fragment, can produce the three output lines in *any order*.
There is *no* defined order of evaluation of the three function
calls. The only thing that "precedence" has determined is that
the return values from b() and c() will seem to be multiplied, and
the return value from a() will seem to be added to that, in terms
of the final result -- and all this assumes that the person who
wrote your compiler used an operator-precedence grammar in the
first place!

(The ISO C standard does not use such a grammar; instead, it uses
a "fully factored" grammar, where the question of whether to "see"
3+4*5 as (3+4)*5 or 3+(4*5) never even comes up. In such a grammar,
there is only one way to "see" the expression at all. Such grammars
are usually difficult for people to work with, but no problem for
very fast idiots like computers.)

Getting back to the original remark, then:

>I'm seeing the "*X++ = Y;" idiom a lot in the code
>and its causing me some problems. According to K&R the ++ (both
>prefix and postfix) operators have the same precedence as * and those
>operators are evaluated right to left. So "*X = Y; X++;" would be
>equivalent code.

Not *exactly* equivalent, but if X and Y are ordinary variables,
this would have the same semantic effect: *X would take on the
value of Y, and X would get incremented. (If "X" is "volatile"
there may be subtle differences.) The indirection will happen
using the "pre-incrementation" value of X.

The phrase "have the same precedence as" really means "use the
associativity rule when deciding how to `bind' the operator and
its operand." The associativity rule here is "right to left".
This does not set the order of evaluation at runtime, just the
order of grouping -- parenthesizing, if you will -- at parse time.
To group the operators in this expression "*X++", use the "right
to left" rule:
*X++ [two operators that could bind to X, with "same precedence"]
*(X++) [bind the one on the right]
Now there is only one operator/operand pair to bind, so the "*"
attaches to the parentheses.

>Fair enough, BUT Stroustrup says postfix ++ has higher precedence
>than prefix ++ and * (which have equivalent precedence). This means
>that "*X++ = Y;" would be rewritten as "X++; *X = Y;".

No: this simply means that, when you go to build a parse tree --
which has little to do with actual evaluation order -- you must
bind a postfix "++" to some expression first, before binding any
prefix "++" or prefix "*". So now:
*X++ [two operators, but "++" has "higher precedence"]
*(X++) [so bind the ++ to the X]
Now we are back to the same situation we had as before, in C. The
whole expression "means" "assign Y to *X, and also increment X;
and when you do the assignment to *X, use the value X had before
the increment happened, no matter when the increment actually
happens."

You might ask: Why does C++ need an extra level of precedence,
then? Well, of course, it does not "need" any such thing -- all
we have to do is resort to one of those grammars that people are
no good at, to remove the problem. But if we did that, *people*
will not be able to work with the language.

Alas, I cannot come up with an example off the top of my head for
where C++ uses this rule productively, and I am running out of time
for this posting. So I will have to leave that step to someone
else. :-)
--
In-Real-Life: Chris Torek, Berkeley Software Design Inc
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@.
Note: PacBell news service is rotten

Lawrence Kirby

unread,
Mar 17, 2001, 4:10:29 PM3/17/01
to
In article <kj4rwspk...@alpha0.bioch.virginia.edu>

w...@alpha0.bioch.virginia.edu "William R. Pearson" writes:

>
>I recently received this email, and, not being a C++ programmer, was
>surprised that there might be an inconsistency:
>
>================
>
>I'm seeing the "*X++ = Y;" idiom a lot in the code
>and its causing me some problems. According to K&R the ++ (both
>prefix and postfix) operators have the same precedence as * and those
>operators are evaluated right to left.

This means that *X++ is grouped as *(X++)

> So "*X = Y; X++;" would be equivalent code.

Given the postincrement property of suffix ++, yes.

> Fair enough, BUT Stroustrup says postfix ++ has
>higher precedence than prefix ++ and * (which have equivalent
>precedence).

That's equivalent to saying that these operators have equal precedence
and right associativity. Because postfix ++ has higher precedence then
*X++ is grouped as *(X++) i.e. the operand X gets bound to the higher
precedence operator. This is exactly the same as above.

> This means that "*X++ = Y;" would be rewritten as "X++;
>*X = Y;".

No, that would make the ++ in *X++ a pre-increment operator. Postfix ++
always prduces the original value of its operand as its result. Precedence
and associativity have no relevance to when a side-effect occurs.
What we know is that X will end up with a value one more than the value it
started with, but irrespective of when that happens that happens the
operand of the * operator will be the original value of X.

>Should I assume that "*X = Y; X++;" is what is desired?

Or

X++; *(X-1) = y;

Or

tmp = X; X++; *tmp = Y;

It is all the same.

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

Micah Cowan

unread,
Mar 19, 2001, 3:02:55 AM3/19/01
to
to...@elf.bsdi.com (Chris Torek) writes:

> Computers are basically very fast idiots,

Chris - Do you mind if I use this in my .sig?

Micah

0 new messages