Type names

A type name, is required in several contexts as something that you must specify without declaring an object; for example, when writing an explicit cast expression or when applying the sizeof operator to a type. Syntactically, the name of a data type is the same as a declaration of a function or object of that type, but without the identifier.

To read or write a type name correctly, put an "imaginary" identifier within the syntax, splitting the type name into simpler components. For example, int is a type specifier, and it always appears to the left of the identifier in a declaration. An imaginary identifier is unnecessary in this simple case. However, int *[5] (an array of 5 pointers to int) is also the name of a type. The type specifier int * always appears to the left of the identifier, and the array subscripting operator always appears to the right. In this case, an imaginary identifier is helpful in distinguishing the type specifier.

As a general rule, the identifier in a declaration always appears to the left of the subscripting and function call operators, and to the right of a type specifier, type qualifier, or indirection operator. Only the subscripting, function call, and indirection operators may appear in a type name declaration. They bind according to normal operator precedence, which is that the indirection operator is of lower precedence than either the subscripting or function call operators, which have equal ranking in the order of precedence. Parentheses may be used to control the binding of the indirection operator.

It is possible to have a type name within a type name. For example, in a function type, the parameter type syntax nests within the function type name. The same rules of thumb still apply, recursively.

The following constructions illustrate applications of the type naming rules.

Table 17. Type names
Syntax Description
int *[5] array of 5 pointers to int
int (*)[5] pointer to an array of 5 integers
int (*)[*] pointer to an variable length array of an unspecified number of integers
int *() function with no parameter specification returning a pointer to int
int (*)(void) function with no parameters returning an int
int (*const [])(unsigned int, ...) array of an unspecified number of constant pointers to functions returning an int. Each function takes one parameter of type unsigned int and an unspecified number of other parameters.

The compiler turns any function designator into a pointer to the function. This behavior simplifies the syntax of function calls.

int foo(float);   /* foo is a function designator */
int (*p)(float);  /* p is a pointer to a function */
p=&foo;           /* legal, but redundant         */
p=foo;            /* legal because the compiler turns foo into a function pointer */

C++ In C++, the keywords typename and class, which are interchangeable, indicate the name of the type.

Related information