Search code examples
cenumsmacros

Are enums appropriate for masks?


Since mask values are integers we can represent them in different ways. For example, as macros:

#define ENABLE_FEATURE_A 0x1
#define ENABLE_FEATURE_B 0x2
#define ENABLE_FEATURE_C 0x4
#define ENABLE_FEATURE_D 0x8

Or enums:

typedef enum {
  FEATURE_A = 0x1,
  FEATURE_B = 0x2,
  FEATURE_C = 0x4,
  FEATURE_D = 0x8
} enabled_features_t

I argue that the enum representation is not appropriate for masks because masks are intended to be combined (with bitwise operations). C requires casting of enums to int because we aren't expected to perform operations on numbers that may not have a meaning. So I would think using macros is more appropriate for flags. Am I overthinking this?


Solution

  • No, enumeration constants are not suitable for bit masks, for two reasons:

    • Enumeration constants are of type int which is signed, and therefore it is an unfortunate type to mix with bitwise operations in particular, since many bitwise operations like shifts invoke various forms of poorly-defined behavior when used on signed types.
    • They are too small. You can't fit the number 0x80000000 inside an enumeration constant, so it simply can't be practically used to bit mask a 32 bit number.

    The appropriate solution as of today (ISO C 9899:2018) is to use #define with integer constants ending with an U/u suffix.


    The upcoming C23 standard will solve this however. It will become possible to use this:

    typedef enum : uint32_t
    {
      FEATURE_X = 0x80000000
    } enabled_features_t;
    

    Now the equivalent type used for enum objects of this type, as well as the enumeration constant, is uint32_t.