On 05/10/2014 05:16 PM, Barry Schwarz wrote:
....
Two types are compatible if there is an implicit conversion from one
to the other. For example, from int to long, long to int, int to
double, pointer to void to any other pointer type.
Compatible scalar types can be implicitly converted to each other, but
most implicit conversions apply to types that are not compatible with
each other. Also, aggregate types can be compatible, but cannot be
implicitly converted.
The standard says that two types are compatible only in certain specific
cases:
(6.2.7p1):
"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.55) Moreover two structure, union, or
enumerated types declared in separate translation units are compatible
if their tags and members satisfy the following requirements: If one is
declared with a tag, the other shall be declared with the same tag. If
both are completed anywhere within their respective translation units,
then the following additional requirements apply: there shall be a
one-to-one correspondence between their members such that each pair of
corresponding members are declared with compatible types; if one member
of the pair is declared with an alignment specifier, the other is
declared with an equivalent alignment specifier; and if one member of
the pair is declared with a name, the other is declared with the same
name. For two structures, corresponding members shall be declared in the
same order. For two structures or unions, corresponding bit-fields shall
have the same widths. For two enumerations, corresponding members shall
have the same values."
Note that "two structure, union, or enumerated types declared in" the
same translation unit are NOT compatible, not even if they meet all of
those other requirements.
Here are the "additional rules" referred to by that clause, in their
entirety:
6.7.2.2p4:
"Each enumerated type shall be compatible with char, a signed integer
type, or an unsigned integer type. The choice of type is
implementation-defined, ..."
6.7.3p10:
"For two qualified types to be compatible, both shall have the
identically qualified version of a compatible type ..."
6.7.6.1p2:
"For two pointer types to be compatible, both shall be identically
qualified and both shall be pointers to compatible types."
6.7.6.2p10: "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."
The fact that types with differing qualifiers (and pointers to those
types) are NOT compatible is the key thing that renders invalid a lot of
code that does things with qualified types that should NOT be done. For
instance, declaring a variable with 'const' in one translation unit, and
without it in another.
The standard never defines directly what "compatible type" means. It
only defines a single general case (same type) and a small number of
special cases. It then goes on, in a variety of places, to require that
under certain circumstances, it is a constraint violation or undefined
behavior for two types to be incompatible.
From what the standard does say, you can derive a few things that the
standard does not say, at least not directly: compatible types are
required to be implemented in essentially the same way, even if they're
not the same type. At a minimum, they have to have the same
representation, alignment requirement, and must be treated equivalently
as function arguments or function return values.