Search code examples
cenumsembeddedkeil

type of enumeration constants inside enumerator list in C


EDITED

I'm currently working on an multi-platform enumeration parser and found this weird behaviour while trying to answer the question above.

Question A)

Does C standard determine the type of the enumeration constants before the enumeration declaration is completed?

For Keil ARMCC, for example:

enum e {
    VAL0 = (signed char)126,
    VAL1,
    VAL2, 
    SIZE0 = sizeof(VAL0), 
    SIZE1 = sizeof(VAL1), 
    SIZE2 = sizeof(VAL2) 
};

I get SIZE0 = 1, SIZE1 = 1, SIZE2 = 8. (if I evaluate the size of the enum constants outside the definition, all have size of int).

Shouldn't they all be equal to sizeof( int )? (Remembering that int, in this case, has size of 4 bytes.)

Question B)

For Keil C251, I have the following:

signed int VALUE0 = (signed char)-1;
enum{ VALUE1 = (signed char)-1 };
enum{ VALUE2 = -1 };
printf( "Is VALUE0 equal to VALUE1? ---> %s", VALUE0 == VALUE1 ? "Yes!" : "No!" );
printf( "Is VALUE0 equal to VALUE2? ---> %s", VALUE0 == VALUE2 ? "Yes!" : "No!" );

which prints:

Is VALUE0 equal to VALUE1? ---> No!
Is VALUE0 equal to VALUE2? ---> Yes!

Shouldn't both print yes?

is there a difference between the definitions of VALUE0 and VALUE1 that I'm missing, maybe the type cast? Or is this probably a compiler bug?


Solution

  • In C (unlike C++), an enumeration constant is of type int. It's legal to refer to an enumeration constant before the end of the type declaration.

    If Keil ARMCC is giving you sizeof(VAL0) != sizeof (int), where VAL0 is an enumeration constant, then Keil ARMCC is not a conforming C compiler. I've seen other questions here that indicate that it's non-conforming.

    Being non-conforming is not necessarily a compiler bug (unless the vendor claims that it's conforming, but as far as I know they don't).

    As for part B:

    enum e{
        MIN_SIGNED_CHAR_0 = (signed char)( -128 ),
        MIN_SIGNED_CHAR_1 = -128,
        MIN_SIGNED_CHAR_2 = (  signed int)(signed char)( -128 ),
        MIN_SIGNED_CHAR_3 = (unsigned int)(signed char)( -128 ),
        MIN_SIGNED_CHAR_0_PLUS_1 = MIN_SIGNED_CHAR_0 + 1,
        MIN_SIGNED_CHAR_1_PLUS_1 = MIN_SIGNED_CHAR_1 + 1,
        MIN_SIGNED_CHAR_2_PLUS_1 = MIN_SIGNED_CHAR_2 + 1,
        MIN_SIGNED_CHAR_3_PLUS_1 = MIN_SIGNED_CHAR_3 + 1,
    };
    

    almost any conforming C compiler should give the MIN_SIGNED_CHAR_{0,1,2} constants the value -128 (of type int), and the MIN_SIGNED_CHAR_{0,1,2}_PLUS_1 constants the value -127 (also of type int). The only possible wiggle room would be for an implementation with SCHAR_MIN == -127, which is possible but unlikely, and apparently is not the case for the Keil compiler(s). If you're getting different results, either it's a bug in the compiler.

    But the definition of MIN_SIGNED_CHAR_3 is problematical. The int value -128 is converted to signed char, which doesn't change the value. That is then converted to unsigned int which yields UINT_MAX+1-128 (assuming 32 bits, this is 4294967168). An enumeration constant with a specified value outside the range of int is a constraint violation, requiring a diagnostic. (Did you get a compile-time warning?) The result, if the compiler doesn't reject the program, is undefined.