1
votes

Are operator precedence & associativity rules ever violated in any C/C++ expression?
If so, can you give an example?

Assume the claims of precedence and associativity rules are:

Each operator has a given precedence level, and each precedence level has a given associativity. If a sub-expression is seen by two operators where they expect an operand, it belongs to the one with higher precedence. Ties are broken by associativity.

Edit: Background

The standard defines C/C++ expressions as a CFG, which is much more flexible than a precedence-based parser. For example, it would have been possible to give binary operators asymmetrical "precedence", which would have rendered any precedence table incorrect. However, it appears to me that the design of the grammar was constrained to uphold simple precedence rules. Here are some alleged "counterexamples" that I have come across:

1) a?b,c:d is not interpreted as (a?b),(c:d)

Some claim that the ?: operator exhibits different precedence towards its middle operand than towards its other operands, because a?b,c:d, for example, is not interpreted as (a?b),(c:d). However, neither b nor c occupies a position in which it appears to ?: as its inner operand. By that reasoning a[b+c] should be interpreted as (a[b)+(c]), which is ludicrous.

2) sizeof(int)*a is interpreted as (sizeof(int))*a rather than sizeof((int)(*a))

... because C disallows an uparenthesized cast as sizeof's operator. However, both of these interpretations conform to precedence rules. The confusion comes from the * operator's ambiguity (Is it the binary or the unary operator?). Precedence tables are not meant to resolve operator ambiguities. They are, after all, not operator-symbol-precedence tables. So the operator precedence rules themselves are intact.

3) a+b=c results in syntax error, not semantic error

a+b=c, according to the standard, is invalid C syntax. If C had had a precedence-based parser, it would only have been caught at the semantic level. In C, it so happens that any expression that is not a unary-expression cannot be l-valued. These semantically doomed LHS expressions therefore do not need to be accommodated syntactically. It makes no difference to the language as a whole, and precedence tables needn't be in the business of predicting the syntacticness/symanticness of the error that is going to result from an expression.

3
Why do you ask? The rules are supposed to be "cast in concrete", but there's always the possibility (though remote) of a compiler bug. But far more often the rules are simply misinterpreted by the user.Hot Licks
@HotLicks - it's also possible that the "precedence rules" are wrong. The language definition doesn't talk about precedence.Pete Becker
What do you mean by, "the question is about the language, not the parser"? The syntax parser either correctly reflects the language specification, or else it's non-conforming. So any conforming syntax parser agrees with the language. What's "the parser", if not a conforming parser?Steve Jessop
@HotLicks I agree. See the added background.Museful
@SteveJessop Syntax parser. C takes some syntactic shorcuts that affect the syntax without affecting the language. I've removed that sentence, and added example 3.Museful

3 Answers

6
votes

For one example, the usual precedence table says that sizeof and cast expressions have the same precedence. Both the table and the standard say that they associate right-to-left.

This simplification is fine when you're looking at, say, *&foo, which means the same as *(&foo).

It might also suggest to you that sizeof (int) 1 is legal C++ and that it means the same thing as sizeof( (int) 1 ). But it's not legal, because in fact sizeof( type-id ) is a special thing of its own in the grammar. Its existence prevents sizeof (int) 1 from being a sizeof expression whose operand is a cast-expression whose operand is 1.

So I think you could say that the "sizeof ( type-id )" production in the C++ grammar is an exception to what the usual precedence/associativity tables say. They do accurately describe the "sizeof unary-expression" production.

3
votes

It depends on whether the "rules" are correct. The language definition doesn't talk about precedence, so the precedence tables you see in various places may or may not reflect what the language definition actually requires.

0
votes

Until someone can find a counterexample, I'm going to put forward this as the default answer:

No, C/C++ precedence and associativity rules are never violated.