Sun Studio 12: C User's Guide

6.12 Compatible and Composite Types

With K&R C, and even more so with ISO C, it is possible for two declarations that refer to the same entity to be other than identical. The term “compatible type” is used in ISO C to denote those types that are “close enough”. This section describes compatible types as well as “composite types”—the result of combining two compatible types.

6.12.1 Multiple Declarations

If a C program were only allowed to declare each object or function once, there would be no need for compatible types. Linkage, which allows two or more declarations to refer to the same entity, function prototypes, and separate compilation all need such a capability. Separate translation units (source files) have different rules for type compatibility from within a single translation unit.

6.12.2 Separate Compilation Compatibility

Since each compilation probably looks at different source files, most of the rules for compatible types across separate compiles are structural in nature:

6.12.3 Single Compilation Compatibility

When two declarations in the same scope describe the same object or function, the two declarations must specify compatible types. These two types are then combined into a single composite type that is compatible with the first two. More about composite types later.

The compatible types are defined recursively. At the bottom are type specifier keywords. These are the rules that say that unsigned short is the same as unsigned short int, and that a type without type specifiers is the same as one with int. All other types are compatible only if the types from which they are derived are compatible. For example, two qualified types are compatible if the qualifiers, const and volatile, are identical, and the unqualified base types are compatible.

6.12.4 Compatible Pointer Types

For two pointer types to be compatible, the types they point to must be compatible and the two pointers must be identically qualified. Recall that the qualifiers for a pointer are specified after the *, so that these two declarations

int *const cpi;
int *volatile vpi;

declare two differently qualified pointers to the same type, int.

6.12.5 Compatible Array Types

For two array types to be compatible, their element types must be compatible. If both array types have a specified size, they must match, that is, an incomplete array type (see 6.11 Incomplete Types) is compatible both with another incomplete array type and an array type with a specified size.

6.12.6 Compatible Function Types

To make functions compatible, follow these rules:

6.12.7 Special Cases

signed int behaves the same as int, except possibly for bit-fields, in which a plain int may denote an unsigned-behaving quantity.

Another interesting note is that each enumeration type must be compatible with some integral type. For portable programs, this means that enumeration types are separate types. In general, the ISO C standard views them in that manner.

6.12.8 Composite Types

The construction of a composite type from two compatible types is also recursively defined. The ways compatible types can differ from each other are due either to incomplete arrays or to old-style function types. As such, the simplest description of the composite type is that it is the type compatible with both of the original types, including every available array size and every available parameter list from the original types.