Specifying size of enum type in C

Solution 1:

I believe there is a flag if you are using GCC.

-fshort-enums

Solution 2:

Is there a way to tell your compiler specifically how wide you want your enum to be?

In general case no. Not in standard C.

Would it even be worth doing?

It depends on the context. If you are talking about passing parameters to functions, then no, it is not worth doing (see below). If it is about saving memory when building aggregates from enum types, then it might be worth doing. However, in C you can simply use a suitably-sized integer type instead of enum type in aggregates. In C (as opposed to C++) enum types and integer types are almost always interchangeable.

When the enum value is passed to a function, will it be passed as an int-sized value regardless?

Many (most) compilers these days pass all parameters as values of natural word size for the given hardware platform. For example, on a 64-bit platform many compilers will pass all parameters as 64-bit values, regardless of their actual size, even if type int has 32 bits in it on that platform (so, it is not generally passed as "int-sized" value on such a platform). For this reason, it makes no sense to try to optimize enum sizes for parameter passing purposes.

Solution 3:

You can force it to be at least a certain size by defining an appropriate value. For example, if you want your enum to be stored as the same size as an int, even though all the values would fit in a char, you can do something like this:

typedef enum {
    firstValue = 1,
    secondValue = 2,

    Internal_ForceMyEnumIntSize = MAX_INT
} MyEnum;

Note, however, that the behavior can be dependent on the implementation.

As you note, passing such a value to a function will cause it to be expanded to an int anyway, but if you are using your type in an array or a struct, then the size will matter. If you really care about element sizes, you should really use types like int8_t, int32_t, etc.

Solution 4:

In some circumstances, this may be helpful:

typedef uint8_t command_t;
enum command_enum
{
    CMD_IDENT                = 0x00,     //!< Identify command
    CMD_SCENE_0              = 0x10,     //!< Recall Scene 0 command
    CMD_SCENE_1              = 0x11,     //!< Recall Scene 1 command
    CMD_SCENE_2              = 0x12,     //!< Recall Scene 2 command
};

/* cmdVariable is of size 8 */
command_t cmdVariable = CMD_IDENT; 

On one hand type command_t has size 8 and can be used for variable and function parameter type. On the other hand you can use the enum values for assignation that are of type int by default but the compiler will cast them immediately when assigned to a command_t type variable.

Also, if you do something unsafe like defining and using a CMD_16bit = 0xFFFF, the compiler will warn you with following message:

warning: large integer implicitly truncated to unsigned type [-Woverflow]