Question on precedence

L

linq936

Hi,
I am puzzled on this C puzzle:

How to interpret this C statement: sizeof (int) * p
Is that the size of integer type multiplies p or the size of
whatever p points to in integer type?

I think it should be the latter because there are 4 parser tokens
here, sizeof, int, * and p, the first and the second are of same
precedence which are higher than the third and all three operators are
right associativity.

So I would parse the code into sizeof ((int) (* p))

But it does turn right. I have the following test code:

void main() {
int pp = 1;
int* p = &pp;
sizeof (int) * p;
}

I use GCC to compile it and get the following error:

main.c:4: invalid operands to binary *

So compiler takes "*" as multiplication.

Do you see at what point I am wrong?
 
I

Ian Collins

Hi,
I am puzzled on this C puzzle:

How to interpret this C statement: sizeof (int) * p
Is that the size of integer type multiplies p or the size of
whatever p points to in integer type?

I think it should be the latter because there are 4 parser tokens
here, sizeof, int, * and p, the first and the second are of same
precedence which are higher than the third and all three operators are
right associativity.

So I would parse the code into sizeof ((int) (* p))

But it does turn right. I have the following test code:

void main() {

It's probably upset at you for the above!
int pp = 1;
int* p = &pp;
sizeof (int) * p;
}

I use GCC to compile it and get the following error:

main.c:4: invalid operands to binary *

So compiler takes "*" as multiplication.

Do you see at what point I am wrong?
You can't multiply by a pointer, p is an int*
 
R

Richard Tobin

How to interpret this C statement: sizeof (int) * p
Is that the size of integer type multiplies p or the size of
whatever p points to in integer type?

I think it should be the latter because there are 4 parser tokens
here, sizeof, int, * and p, the first and the second are of same
precedence which are higher than the third and all three operators are
right associativity.

Questions like this keep coming up, and the answer is always the
same: C does not use operator precedence to define the grammar,
and tables attempting to summarise the syntax using precedence
are often inadequate. The one you're using seems to be an example,
because sizeof and cast do *not* have the same precedence.

The standard defines the grammar using "production rules". The
operand of sizeof is either a unary-expression or a parenthesised type
name. "(int) * p" does not match the production for unary-expression
and is not a parenthesised type name, so it cannot be the operand of
sizeof.

-- Richard
 
K

Keith Thompson

Ian Collins said:
It's probably upset at you for the above!

You can't multiply by a pointer, p is an int*

Yes, but there is a valid question buried among a number of
unfortunate errors. Depending on how the expression is parsed, this:
sizeof (int) * p
could be either a multiplication whose left operand is a sizeof:
(sizeof (int)) * p /* legal if p is numeric */
or a sizeof whose right operand is a cast of a dereference:
sizeof ((int) * p) /* legal if p is a pointer to some numeric type */

This is similar to the question of whether a+b*c means (a+b)*c)
or a+(b*c). There is a single correct answer: it means a+(b*c),
because multiplication has higher precedence (binds more tightly)
than addition. Likewise, there's a single correct answer for
"sizeof ((int) (* p))".

The syntax for the sizeof operator is:

sizeof unary-expression
sizeof ( type-name )

The expression "sizeof (int) * p" cannot satisfy either of those.
It obviously can't match the second form, because the expression
doesn't end in a ')' character, but what about the first? Well,
"(int) * p" is an expression, but it's *not* a "unary-expression".
Why? Because the syntax for a unary-expression is:

unary-expression:
postfix-expression
++ unary-expression
-- unary-expression
unary-operator cast-expression
sizeof unary-expression
sizeof ( type-name )

unary-operator: one of
& * + - ~ !

In fact, "(int) * p" is a cast-expression:

cast-expression:
unary-expression
( type-name ) cast-expression

(All cast-expressions are unary-expressions, but not vice versa).

The other possibitility is that "sizeof (int) * p" is a
multiplicitive-expression. The syntax for that is:

multiplicative-expression:
cast-expression
multiplicative-expression * cast-expression
multiplicative-expression / cast-expression
multiplicative-expression % cast-expression

Our expression matches the second alternative here. The left operand,
"sizeof (int)", is a unary-expression, which is a cast-expression,
which is a multiplicative-expression. The right operand, "p", is an
identifier, which is a primary-expression, which [skipping a few steps]
is a cast-expression.

You can also make the same argument in terms of relative operator
precedences, but the standard doesn't use that concept.
 
K

Keith Thompson

I am puzzled on this C puzzle:

I've answered your actual question in another followup. I'll take
this opportuntiy to point out some errors that might obscure the
question you're trying to ask.
How to interpret this C statement: sizeof (int) * p

That's an expression, not a statement.
Is that the size of integer type multiplies p or the size of
whatever p points to in integer type?

It's the former; see my other followup for the gory details.
I think it should be the latter because there are 4 parser tokens
here, sizeof, int, * and p, the first and the second are of same
precedence which are higher than the third and all three operators are
right associativity.

There are 6 tokens: sizeof, (, int, ), *, and p.

Tokens don't have precedence. Operators do have precedence, sort of,
but the standard doesn't present expression syntax using that concept.
So I would parse the code into sizeof ((int) (* p))

But it does turn right. I have the following test code:

void main() {

The correct declaration is "int main(void)". If your textbook told
you that "void main()" is correct, get your money back.
int pp = 1;
int* p = &pp;
sizeof (int) * p;
}

I use GCC to compile it and get the following error:

main.c:4: invalid operands to binary *

So compiler takes "*" as multiplication.

Right, and if p had been of some numeric type, it would have compiled
without error.
Do you see at what point I am wrong?

See my other followup.
 
M

Martin Ambuhl

(e-mail address removed) wrote some nonsense in which he claimed to have a
reasonable interptetation of:

sizeof (int) * p

His example code begins
void main() {

At this point we know that anything he might opine about C can be safely
ignored.
[...]
Do you see at what point I am wrong?

Yes.
 
K

Kenny McCormack

(e-mail address removed) wrote some nonsense in which he claimed to have a
reasonable interptetation of:

sizeof (int) * p

His example code begins
void main() {

At this point we know that anything he might opine about C can be safely
ignored.
[...]
Do you see at what point I am wrong?

Yes.

All threads on clc either start out as or quickly degenerate into
discussing "void main()".

The point being that it *is* the one thing we can all agree on.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top