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?
No, enumeration constants are not suitable for bit masks, for two reasons:
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.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
.