In The C Programming Language, 2nd Edition, by authors Brian W. Kernighan and Dennis M. Ritchie, they talk about declarators and direct-declarators. The discussion starts in the book on p. 122 with dcl and direct-dcl's Will you please explain the difference between a declarator and a direct-declarator in and easy to understand way? What makes it direct?
Also, on p. 225
where the direct-declarator is an identifier or a parenthesized identifier. In particular, it must not achieve function type by means of a typedef.
It seems to me that declarators are the declaration of a variable or function. In "T D", the T part specifies its specifiers and types, and the D part specifies the identity, meaning the unique identification name of the variable or function. It has something to do with the language's grammar.
Are declarators indirect since they are not specified as direct, as in direct-declarator?
CodePudding user response:
Even the second edition of K&R is more of historical interest these days than practical interest.
Nevertheless, the terms "declarator" and "direct declarator" continue in use in the current C language specification. The language spec describes the former this way:
Each declarator declares one identifier, and asserts that when an operand of the same form as the declarator appears in an expression, it designates a function or object with the scope, storage duration, and type indicated by the declaration specifiers.
(C17 6.7.6/2)
It follows that "declaration specifiers" are separate from "declarators". In fact, a declarator is the part of a declaration that specifies what is being declared.
"Direct declarators" is a subset of declarators. The "direct" is meant to contrast with "indirect", as in pointers. For example, given
int i;
int *p;
The i
and *p
and p
are all syntactically declarators, but of those, only i
and p
are direct declarators. And only i
and *p
are full declarators, which are those that do not appear as part of another declarator (as declarator p
does).
It gets more complicated than that -- for example, enclosing any declarator in parentheses yields a direct declarator, even if by itself, the original declarator is not a direct one.
Overall, this is a syntactic distinction that you probably don't need to worry too much about unless you are writing a parser for the C language. And if you are doing that, then you really need to be looking at the formal syntax descriptions.
CodePudding user response:
Loosely speaking, a declarator is a complete declaration, while a direct declarator is either an identifier by itself or an identifier followed by []
(making it an array) or ()
(making a function or function pointer).
The complete definition of these terms can be found in the syntax for a declarator which can be found in section 6.7.6p1 of the C11 standard:
declarator:
- pointeropt direct-declarator
direct-declarator:
- identifier
(
declarator)
- direct-declarator
[
type-qualifier-listopt assignment-expressionopt]
- direct-declarator
[
static
type-qualifier-listopt assignment-expression]
- direct-declarator
[
type-qualifier-liststatic
assignment-expression]
- direct-declarator
[
type-qualifier-listopt*
]
- direct-declarator
(
parameter-type-list)
- direct-declarator
(
identifier-listopt)
pointer:
*
type-qualifier-listopt*
type-qualifier-listopt pointertype-qualifier-list:
- type-qualifier
- type-qualifier-list type-qualifier
parameter-type-list:
- parameter-list
- parameter-list
,
...
parameter-list:
- parameter-declaration
- parameter-list
,
parameter-declarationparameter-declaration:
- declaration-specifiers declarator
- declaration-specifiers abstract-declaratoropt
CodePudding user response:
The grammar needs a direct-declarator token to specify precedence. As it is, * foo [ 3 ]
must be parsed as a declarator that is *
followed by a direct-declarator that is foo [ 3 ]
. If the grammar did not separate a declarator and a direct-declarator, it could be unclear whether this was *
followed by foo [ 3 ]
grouped together or was * foo
grouped together followed by [ 3 ]
.
The grammar says a declarator is:
- pointeropt direct-declarator
where pointer is *
followed by optional qualifiers (like const
) and direct-declarator is one of:
- identifier
(
declarator)
- direct-declarator
[
type-qualifier-listopt assignment-expressionopt]
- direct-declarator
[
static
type-qualifier-listopt assignment-expression]
- direct-declarator
[
type-qualifier-liststatic
assignment-expression]
- direct-declarator
[
type-qualifier-listopt *]
- direct-declarator
(
parameter-type-list)
- direct-declarator
(
identifier-listopt)
So, given * foo [ 3 ]
, we must take this as a declarator with *
for pointer and foo [ 3 ]
for direct-declarator. There is no way to have *
at the start of a direct-declarator. Thus, * foo [ 3 ]
must declare an array of 3 pointers, not a pointer to an array of 3 elements.
If those options for declarator and direct-declarator were merged into a single grammar token, then the parsing would be ambiguous. You could parse it as * foo [ 3 ]
being that * foo
is a declarator followed by [ 3 ]
, which is not what we desire.
The name is of no great significance; we merely need another name for the additional token. There are other examples of this in the C grammar. Notably, the expressions grammar starts with expression and then goes through a chain of assignment-expression, conditional-expression, logical-OR-expression, and so on. These have names associated with the operators they involve, until you get to primary-expression. That has some semantic similarity to direct-declarator, suggesting they are both named in the spirit of “okay, we got to the bottom of this grammar chain, here is the primary/direct token.”