I have just finished reading through the language reference ( appendix A) of the 2nd edition of K&R's "The C Programming language" for a new job.
Please note, that I have worked out how to read C declarations by all the guidance here on SO ( so thanks ;) ). The explanation has always been a reference to the precedence of expressions and operators in C.
I can infer the same precedence table from the Reference Manual a.k.a. Appendix A, §A7 in said book, no problem.
However, §A7 deals with the precedence of expression operators, as is said at the beginning of the section - the square brackets postfix-expression [ expression ]
are herein viewed as the subscript operator, the asterisk *
is viewed as the indirection operator and parentheses ( argument-expression-list)
or ()
pertain to function calls, see §A7.3.
So why do so many people refer to this precedence table, when the subject is C declarations, and even get a couple of upvotes on SO? The only precedence it claims to define is that of certain expression operators.
How declarations are to be parsed is written in §A8, especially §A8.6 goes into the basics of more complicated declarations.
But throughout the whole of Appendix A, there are no statements about in what precedence exactly parentheses, square brackets, asterisks, type names and so on are to be parsed.
On page 216 it says, that parentheses may change the binding of complex declarators, but now how ( although I have a hunch, see below in my example).
Let me give you an example in 'pseudo-code' where I am was at a loss, using §A8.8 ( the T's stand for the type specifiers, the D's for the declarators):
Reading a C declaration:
Original declaration:
char (*(*f())[])()
/* Have to use A8.6.3, because of how the decl. looks: */
Now let T=char , D=(*(*f())[])()
D=D1(), where D1=(*(*f())[])
The type of f, according to A8.6.3 is then
:L1 /* label 1 */
f is "type-modifiers of f in D1" function returning char /* note, in the book it says 'type-modifiers of f in T D1, but this wouldn't make any sense! */
Now look at T D1 = char (*(*f())[])
:ALT_A
The type of f in D1 = (*(*f())[]) is the same as that of f in
D2=*(*f())[]
/* At least, this is how parentheses are supposed to be understood, according to the beginning of A8.6,
where it says:
In a declaration T D where D has the form
( D1 )
then the type of the identifier in the declaration D1 is the same as that of D. */
/* note about that quote: the identifier in D has no type, did the authors mean to imply 'incomplete' types?
So, using incomplete types:*/
Looking at D2 = T1 D3[] ----> have to use A8.6.2, where T1 = * , D3 = (*f()),
so the type of f in T1 D3 is
f is "type-modifiers of f in D3" array of pointers ()
look at f in D3 = (*f()), or equivalently, f in D4 = *f(). Have to use A8.6.3. --->
f is a function returning a pointer to ()
going up a level: f is "type-modifiers of f in D3" array of pointers ()
translates to: f is a function returning a pointer to an array of pointers ()
going up another level: f is "type-modifiers of f in D1" function returning char
translates to: f is a function returning a pointer to an array of pointers to functions returning a char
This is the result, cdecl also shows. Note that I haven't used any precedence table, just the reference manual and the sections directly pertaining declarations.
So how and why do so many people refer to operator precedence?
It seems to me like every reference to operator precedence when people ask about C declarations is a wrong answer giving a "parsing algorithm" that magically turns out to give the right result.
And secondly, how come that K&R seem to be so inexact with so many things ( see my /* */-remarks in the pseudo-code)? I would have expected more precision, I mean they obviously knew all the details and had to be able to think precise.
Sorry for the messed up formatting, btw.. I have spent most of this day trying to write down how I manually parse this and at the same time understanding what K&R might have meant with this and that formulation...
List of sources, where declarations and operator precedence are said to be connected:
http://users.ece.utexas.edu/~ryerraballi/CPrimer/CDeclPrimer.html ("All one has to understand any complex C declaration then, is to know that these declarations are based on the C operator precedence chart, the same one you use to evaluate expressions in C:")
http://binglongx.com/2009/01/25/how-to-read-a-cc-declaration/
How are (complex) declarations parsed in terms of precedence and associativity? ("In fact, the designers of C were wise enough to make declarations use the same "precedence rules" as expressions. This is the "declaration follows usage" rule. For example, in the expression", see first answer by Brian .)
Operator precedence in C Definitions
Expert C Programming: Deep C Secrets, p. 74, 28 5 star reviews on Google Books?