How to Understand C's Declaration Syntax

Many programming languages employ a declaration syntax which emphasises the type of the name being declared. But C did something different: its syntax emphasises the type of expressions using the declared name.

This is key to an intuitive understanding of declarations like this (extreme) example from from FreeBSD's manual page for signal(3):

void (*signal(int sig, void(*func)(int)))(int)

It is also the reason that C programmers conventionally say int *x and not int* x (note the spaces), and why declarations like int *x, *y, z make any sense.

In a 1996 paper1, Dennis Ritchie wrote about the choice of syntax:

For each object of such a composed type, there was already a way to mention the underlying object: index the array, call the function, use the indirection operator on the pointer. Analogical reasoning led to a declaration syntax for names mirroring that of the expression syntax in which the names typically appear. Thus,

int i, *pi, **ppi;

declare an integer, a pointer to an integer, a pointer to a pointer to an integer. The syntax of these declarations reflects the observation that i, *pi, and **ppi all yield an int type when used in an expression. Similarly,

int f(), *f(), (*f)();

declare a function returning an integer, a function returning a pointer to an integer, a pointer to a function returning an integer;

int *api[10], (*pai)[10];

declare an array of pointers to integers, and a pointer to an array of integers. In all these cases the declaration of a variable resembles its usage in an expression whose type is the one named at the head of the declaration.

More examples should help cement this idea:

So signal turns out to be a function returning a pointer-to-function. It takes two arguments, one of which is also a pointer-to-function.

These rules do not quite hold for C++, which has a "heavier emphasis on types" than its predecessor. For instance, reference variables, declared like

int& x = y;

don't require the use of an & to get at the referenced object. In this example the type of the expression x is int and x is indistinguishable from y, see [expr.type]​.

Also worth mentioning is https://cdecl.org, which can be used to convert C declarations into a psuedo-English description – occasionally useful for checking your understanding of a complicated declaration.

Footnotes:

1

Dennis Ritchie. History of Programming Languages-II. Thomas J. Bergin, Jr. and Richard G. Gibson, Jr. ACM Press (New York) and Addison-Wesley (Reading, Mass), 1996; ISBN 0-201-89502-1

Author: Max Bozzi

Created: 2022-02-02 Wed 22:25

Validate