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

Operator precedence.

2 views
Skip to first unread message

Matt Bayliss

unread,
Jun 26, 2001, 7:20:14 PM6/26/01
to
Hi there,

In my C book I have a table of operator precedence. Three of the rows are:

! ~ ++ -- + - * & (type) sizeof
* / %
+ -

As you can see + - * appears on the first line with * / and + - appearing
again later.

What is the meaning of this? Is * on the first line the multiplication
operator? I would have thought it was the one on the 2nd line.as it is next
to the /.

Basically I want to take the size of a structure, multiply it by the amount
of elements I want that structure to have to obtain the number of bytes I
need to pass to realloc().

I have written the following, can anyone confirm I have done the right thing
in terms of ()'ing the right bits. MDBStructPtr_p is a
pointer-to-pointer-to-struct.

if( ( newpointer = realloc( *MDBStructPtr_p, sizeof(struct MDBDataStruct) *
(MDBHitCounter + 1) ) ) != NULL )

;

Ta,

Matt

Daniel Bishop

unread,
Jun 26, 2001, 8:03:37 PM6/26/01
to
"Matt Bayliss" <gr...@hiddenemail.com> wrote in message
news:9hb58f$sn1$1...@taliesin.netcom.net.uk...

> What is the meaning of this? Is * on the first line the multiplication
> operator? I would have thought it was the one on the 2nd line.as it is
next
> to the /.

The * operator has two different uses in C. The first * in that table is
used to dereference pointers; the second is the multiplication operator.


Tom St Denis

unread,
Jun 26, 2001, 8:26:19 PM6/26/01
to
Matt Bayliss wrote:
>
> Hi there,
>
> In my C book I have a table of operator precedence. Three of the rows are:
>
> ! ~ ++ -- + - * & (type) sizeof
> * / %
> + -
>
> As you can see + - * appears on the first line with * / and + - appearing
> again later.
>
> What is the meaning of this? Is * on the first line the multiplication
> operator? I would have thought it was the one on the 2nd line.as it is next
> to the /.

The first line is unary operators. +/- are the positive, negative unary
operators, & is address of, * is derefence, etc...

so 5 * *a + c means (5 * (load value pointed to by a)) + c

> Basically I want to take the size of a structure, multiply it by the amount
> of elements I want that structure to have to obtain the number of bytes I
> need to pass to realloc().
>
> I have written the following, can anyone confirm I have done the right thing
> in terms of ()'ing the right bits. MDBStructPtr_p is a
> pointer-to-pointer-to-struct.
>
> if( ( newpointer = realloc( *MDBStructPtr_p, sizeof(struct MDBDataStruct) *
> (MDBHitCounter + 1) ) ) != NULL )
>

That should be ok. Actually I don't think you need the dereference * on
"MDBStructPtr_p" unless it's a pointer to a pointer.

Tom

Barry Schwarz

unread,
Jun 26, 2001, 11:05:58 PM6/26/01
to

Your first row is the unary operators. + and - have the usual unary
meaning and the * is the dereference operator. These are not
addition, subtraction, and multiplication. Consider
x = y / -*z;

Your second and third row are the normal binary arithmetic operators.

Your realloc call is OK but most of the regulars here prefer
sizeof *newpointer
instead of
sizeof(struct MDBDataStruct)


<<Remove the del for email>>

Chris Torek

unread,
Jul 3, 2001, 10:01:13 PM7/3/01
to
In article <9hb58f$sn1$1...@taliesin.netcom.net.uk>
Matt Bayliss <gr...@hiddenemail.com> writes:
>In my C book I have a table of operator precedence. ...

It is worth noting here that C (as defined by the ANSI/ISO standards
at least) does not actually have any operator precedence.

This *sounds* wrong, because as everyone knows, given something
like:

i = 3 + 4 * 5;

any C compiler must set i to 23 (4*5 gives 20, plus 3 is 23), not
35 (3 plus 4 gives 7, times 5 is 35). But "operator precedence"
is not the method by which this is achieved.

In computer science, particularly the field of grammars and parsing
-- the stuff a C compiler does to figure out what some C expression
"means" at some low level -- the term "operator precedence" has a
very specific meaning. An "operator precedence grammar" lists
expression operators and their precedence (which rather nicely
matches the name, "operator precedence"). Such a grammar must also
usually list the operators' associativity, if any. All of this
stuff is merely used to "break ties" in what would otherwise be
multiple, legal "parses" for some expression.

These ties, which must be broken in some way or another, arise from
what is called an "ambiguous grammar". A grammar like:

expr: constant
| expr '+' expr
| expr '-' expr
| expr '*' expr
| expr '/' expr;

(in yacc-like "BNF") means that an "expr" can be built by reading
some "constant" such as 3, or by reading any "expr" followed by a
plus sign followed by any other "expr", or by reading any "expr"
followed by a '*' followed by any other "expr". That gives two
ways to read "3 + 4 * 5". For instance, "3 + 4" is certainly
"constant + constant", which is a valid "expr". So that can be
the first "expr" in "expr * expr". Then 5 is another constant,
which is also a valid expr. This gives a valid "expr", a '*', and
another valid expr. Overall, then, this is:

*
/ \
+ 5
/ \
3 4

or in other words, (3 + 4) * 5, or 35. But that is not what you
would want if you were parsing C; instead, you would want the
parser to see the first 3 as an "expr" all by itself, followed
by a "+" and another expr. You would want the second "expr" to
match up with the "4 * 5" part, giving this:

+
/ \
3 *
/ \
4 5

Technically, what you want is for the parser to "bind" the
four-times-five expression more tightly than the three-plus-expr
expression. Once they are bound into some "expr", that "expr"
will then be available to bind to other "expr"s, such as (3+expr).

The obvious and easy way to do this is to use an "operator precedence
grammar" and tell the parser to bind "times" more tightly than
"plus", so that in the absence of parentheses to force (3+4) to
bind first, the (4*5) part will bind first.

The ANSI/ISO C standard authors, however, elected to do things the
hard way. Instead of using an operator precedence grammar, they
used an alternative called a "fully factored" grammar. Such a
thing is large and cumbersome and consists of lots of tiny little
painfully exact and boring steps -- just what computers are good
at, and humans are bad at. This means that C does not have
"operator precedence" at all, in some sense.

Fortunately, it turns out that the fully factored grammar in the
C standard is completely compatible with a much simpler (for humans
anyway) "operator precedence" grammar. Thus, instead of memorizing
just where to put each "cast-expression" and "additive-expression"
and "multiplicative-expression" and "logical-OR-expression" and
"primary-expression" and "shift-expression" and, well, you get the
idea -- instead of learning a ton of useless nonterminal symbols
(as they are called), you can just make up a precedence table.
This is much shorter and more wieldy. So, C books do that.

Alas, there is a pitfall here.

Note that I keep saying "bind first", not "happen first". C not
only does not use an operator precedence grammar, it also carefully
(or perhaps carelessly :-) ) has a complicated series of rules
about "sequence points" that mark points in the running of a program
where you can say "something occurred BEFORE this, and AFTER that".
It is sequence points, and sequence points alone, that impose any
actual evaluation order on any C expression. (Statements have
their own order, especially with loop constructs and "goto"
statements.) So even though, in 3+4*5, the 4*5 "binds" first, it
does not necessarily have to "evaluate" first. The C system can
first evaluate the 3 (giving 3), then evalulate the 4*5 (giving
20), then evaluate the "+" part (giving the final correct answer
of 23). Or, it can fully evaluate the 4*5 part first, and then
do the 3 -- or it can even do them all at the same time!

For a simple expression like 3+4*5 it does not matter, but for
something like:

f() + g() * h()

the actual order can easily be seen, simply by having each function
(f, g, and h) print its name to stdout. In this case, as long as
each function is a function, the C standard promises you (the
programmer) that as soon as f() starts, f() will run until it is
done and "return"s a value, and as soon as g() starts, it will also
run to completion, and the same holds for h(). It does *not*
promise anything about the order in which f(), g(), and h() themselves
will run -- just that, once started, each one runs to completion.

Thus, there are two things to remember here:

- C does not really have "operator precedence", but you can fake it
and not get burned, as long as you remember that...
- "precedence" does *not* determine order of evaluation at run time;
"sequence points" do that.

Back to the original question:

>! ~ ++ -- + - * & (type) sizeof
>* / %
>+ -
>
>As you can see + - * appears on the first line with * / and + - appearing
>again later.

The first ones are the unary versions of the operators; the second
are the binary version. (This actually hints at a glitch with
operator precedence grammars. Typically one decorates the grammar
with directives saying "when you see a '-' give it a middling
precedence like 3; when you see a '*' give it higher precedence,
such as 2". When the parser sees a unary minus, though, it needs
a different -- higher -- precedence than for a subtractive minus.
Yacc uses yet more special directives to accomplish this. In other
words, first you give a bunch of directives to establish precedence
and associativity, then you write the expression grammar and stick
in *more* rules to override the usual rules when encountering one
of the exceptions. If you write out a fully-factored grammar, this
problem never occurs. [The problem that occurs instead is that
you go crazy and start mumbling thousands of sub-rules. :-) ])
--
In-Real-Life: Chris Torek, Wind River Systems
El Cerrito, CA, USA Domain: to...@bsdi.com +1 510 234 3167
http://claw.eng.bsdi.com/torek/ (not always up) I report spam to abuse@.

Stefan Farfeleder

unread,
Jul 10, 2001, 9:15:22 AM7/10/01
to

C99 introduces another meaning for '*'. In a function declaration that
isn't at the same time a definition, "[*]" indicates a VLA as opposed to
a "normal" array. Example:

void foo(int, int [*]);

/* ... */

void foo(int n, int a[n])
{
/* ... */
}

ICBW.

--
Stefan Farfeleder

David Thompson

unread,
Jul 14, 2001, 1:00:12 AM7/14/01
to
Chris Torek <to...@BSDI.COM> wrote :
...

> The ANSI/ISO C standard authors, however, elected to do things the
> hard way. Instead of using an operator precedence grammar, they
> used an alternative called a "fully factored" grammar. ...

Harder for the average programmer to understand, I agree
(except for the mathematically-minded) but not I think for
the average language designer or compiler implementor.
And in addition to precedence it encodes associativity
by the choice of left or right recursion.

> Fortunately, it turns out that the fully factored grammar in the
> C standard is completely compatible with a much simpler (for humans

> anyway) "operator precedence" grammar. ...

Except for cast vs some prefix and ?: vs assignment. Fortunately
programmers who actually use those anomalous cases are few,
and getting fewer every time we catch up to one. <G>

> This is much shorter and more wieldy. So, C books do that.
>

Also rather more effable. But what I want to know is, why can't you
ever find von sale things there were furbished just once? <G>

> - C does not really have "operator precedence", but you can fake it
> and not get burned, as long as you remember that...
> - "precedence" does *not* determine order of evaluation at run time;
> "sequence points" do that.
>

Abso-expletive-lutely!

--
- David.Thompson 1 now at worldnet.att.net

0 new messages