Search code examples
ctypeslanguage-lawyercompatibilityterminology

What does it mean exactly if two types are "compatible" to each other in C?


In the C standard is stated (emphasize mine):

Two types have compatible type if their types are the same. Additional rules for determining whether two types are compatible are described in 6.7.2 for type specifiers, in 6.7.3 for type qualifiers, and in 6.7.6 for declarators. 56)

56)Two types need not be identical to be compatible.

Source: C18, §6.2.7/1 - "Compatible type and composite type"

The information I get from these sentences is not much and not very helpful. The cited sections in general also provide no further information about what "compatible" exactly is/means.

I know now, that two types are compatible if they have the same type, but also can be compatible if they don't have the same type/be identical.

One place I found out where two non-identical types are compatible to each other is if I compare one type to a typedefd type of this original type or to any typedefd type of the original type, both types are compatible, as explained in the examples to §6.7.8/4 and /5:

§6.7.8/4:

EXAMPLE 1 After

typedef int MILES, KLICKSP(); 
typedef struct {doublehi, lo; } range;

the constructions

MILES distance; 
extern KLICKSP *metricp;
range x;
range z,*zp;

are all valid declarations. The type of distance is int, that of metricp is "pointer to function with no parameter specification returning int", and that of x and z is the specified structure; zp is a pointer to such a structure. The object distance has a type compatible with any other int object.

and

§6.7.8/5:

EXAMPLE 2 After the declarations

typedef structs1 { int x; } t1, *tp1;
typedef structs2 { int x; } t2, *tp2;

type t1and the type pointed to by tp1 are compatible. Type t1 is also compatible with type structs1, but not compatible with the types structs2, t2, the type pointed to by tp2, or int.

but it only shows one example regarding the typedef, where types can be compatible if not identical.

My questions:

  • Under which (all) circumstances can two types be compatible if they are not identical exactly? , and

  • What is a "compatible type" exactly? / What does it mean if two types are compatible to each other?

  • What specifies "compatibility"?

That is what I am looking for and couldn't found in the standard until yet.

If possible, please refer to sections from standard in the answers.


Additional research:

I discovered that compatibility is not mandatory related to range, representation or behavior:

§6.2.5/15:

The three types char, signed char, and unsigned char are collectively called the character types. The implementation shall define char to have the same range, representation, and behavior as either signed char or unsigned char.45)

45)CHAR_MIN, defined in <limits.h>, will have one of the values 0 or SCHAR_MIN, and this can be used to distinguish the two options. Irrespective of the choice made, char is a separate type from the other two and is not compatible with either.


Cited sections from the first quote:

The cited sections 6.7.2, 6.7.3 and 6.7.6 do not explain more what a compatible type is, they only mandate rules for specific cases when a type shall be a compatible type.

§6.7.2/4:

Each enumerated type shall be compatible with char, a signed integer type, or an unsigned integer type. The choice of type is implementation-defined, 131) but shall be capable of representing the values of all the members of the enumeration. The enumerated type is incomplete until immediately after the } that terminates the list of enumerator declarations, and complete thereafter.

§6.7.3/11:

For two qualified types to be compatible, both shall have the identically qualified version of a compatible type; the order of type qualifiers within a list of specifiers or qualifiers does not affect the specified type.

§6.7.6.1/2:

For two pointer types to be compatible, both shall be identically qualified and both shall be pointers to compatible types.

§6.7.6.2/6:

For two array types to be compatible, both shall have compatible element types, and if both size specifiers are present, and are integer constant expressions, then both size specifiers shall have the same constant value. If the two array types are used in a context which requires them to be compatible, it is undefined behavior if the two size specifiers evaluate to unequal values.

§6.7.6.3/15:

For two function types to be compatible, both shall specify compatible return types.149) Moreover,the parameter type lists, if both are present, shall agree in the number of parameters and in use of the ellipsis terminator; corresponding parameters shall have compatible types. If one type has a parameter type list and the other type is specified by a function declarator that is not part of a function definition and that contains an empty identifier list, the parameter list shall not have an ellipsis terminator and the type of each parameter shall be compatible with the type that results from the application of the default argument promotions. If one type has a parameter type list and the other type is specified by a function definition that contains a (possibly empty) identifier list,both shall agree in the number of parameters, and the type of each prototype parameter shall be compatible with the type that results from the application of the default argument promotions to the type of the corresponding identifier. (In the determination of type compatibility and of a composite type, each parameter declared with function or array type is taken as having the adjusted type and each parameter declared with qualified type is taken as having the unqualified version of its declared type.)

149)If both function types are "old style", parameter types are not compared.


Related:


Solution

  • It actually comes from this:

    1. All declarations that refer to the same object or function shall have compatible type; otherwise, the behavior is undefined.

    So from that you can see that anything that is allowed by the standard to work here, will be by necessity, compatible. For example the type int [] is distinct from int [10] but they are compatible, because the standard allows you to declare

    extern int foo[];
    

    in one file and define

    int foo[10];
    

    in another file, and access foo using the external identifier as an array of unknown size - therefore these types are compatible, but not identical.

    It is stated explicitly in C11/18 6.7.6.2p6:

    1. For two array types to be compatible, both shall have compatible element types, and if both size specifiers are present, and are integer constant expressions, then both size specifiers shall have the same constant value. If the two array types are used in a context which requires them to be compatible, it is undefined behavior if the two size specifiers evaluate to unequal values.