Are an incomplete enum and a complete enum compatible types?

Viewed 127

In one translation unit, I have an enum which is completely defined:

typedef enum E { A, B, C } ET;

In an other one, I only have an incomplete definition of this enum:

typedef enum E ET;

I would like to know if both types are compatible.

The definition of compatible types is described in this page but it seems quite fuzzy for me. There is an explanation when the two enums are completed types but I'm not sure to understand what happens if one is and not the other one.

What should I understand by the following sentence?

one is an enumerated type and the other is that enumeration's underlying type

Does it mean both types are compatible?

3 Answers

Your question is not meaningful. C doesn't have incomplete enums (unlike incomplete arrays or unions or structs), even though many compilers support them when you don't request -pedantic conformance checking.

https://gcc.godbolt.org/z/vTv85v

Oooch right, incomplete enum is a compiler extension like gcc Incomplete-Enums. The rest of the answer assumes that "incomlpete enum" obeys the same rules as incomplete structures and unions.

Are an incomplete enum and a complete enum compatible types?

Yes (if they are named the same).

Does it mean both types are compatible?

Yes. From the cppreference you linked to:

The types T and U are compatible, if

  • they are the same type (same name or aliases introduced by a typedef)

Ie. ET is an alias to enum E in both units - ET is compatible in both units. And later:

  • they are both structure/union/enumeration types, and
    • (C99)if one is declared with a tag, the other must also be declared with the same tag.
    • if both are completed types, blabla

In both enum E has the same tag - E - so they are also compatible. And enum E in second TU is not complete, so the additional points do not apply here.

Let's also mention the original from C11 6.2.7 Compatible type and composite type:

  1. 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.
    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.

What should I understand by the following sentence?

one is an enumerated type and the other is that enumeration's underlying type

Each enum has an "underlying type" - it's not really an enum as a type, it's actually an int or a char or another implementation-defined type. Let's quote C11 6.7.2.2 Enumeration specifiers:

  1. Each enumerated type shall be compatible with char, a signed integer type, or an unsigned integer type. The choice of type is implementation-defined, 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.

The first sentence is rather explicit. This "real type" compiler chooses is dependent - most of the time it's just an unsigned int or int. See your compiler documentation, like gcc implementation define behavior 4.9 Structures, Unions, Enumerations, and Bit-Fields:

The integer type compatible with each enumerated type (C90 6.5.2.2, C99 and C11 6.7.2.2).

Normally, the type is unsigned int if there are no negative values in the enumeration, otherwise int. If -fshort-enums is specified, then if there are negative values it is the first of signed char, short and int that can represent all the values, otherwise it is the first of unsigned char, unsigned short and unsigned int that can represent all the values.

On some targets, -fshort-enums is the default; this is determined by the ABI.

That point one is an enumerated type and the other is that enumeration's underlying type is about that unsigned int and enum E may be compatible types, so you might just as well use an unsigned int.

This record

typedef enum E ET;

is incorrect.

According to the C Standard (6.7.2.3 Tags)

3 A type specifier of the form

enum identifier

without an enumerator list shall only appear after the type it specifies is complete.

So if there is a preceding complete declaration of the enumeration E then the question about compatibility is resolved without a problem. Otherwise the compiler shall issue an error message.

Related