3

I'm trying to use enum in C to create a flags variable, as discussed here: Flags, enum (C)

How should I reset a single enum flag, when the compiler represents the enum as signed?

Problem:

Say I declare my flags type like this:

typedef enum {       
     FLAGS_A = 1 << 0,
     FLAGS_B = 1 << 1,
     FLAGS_C = 1 << 2,
     FLAGS_D = 1 << 3     
} flags_t;

flags_t flags;

I would like to reset a flag like this:

flags |=   FLAGS_A;   // Set A
flags &= (~FLAGS_A);  // Reset A

However the compiler (Microchip XC8 Compiler V2.32) throws an error because bitwise operators should only be used on unsigned types. It looks like the enum is actually a signed integer under the hood.

Based on this question, it looks like there's no good way to force the compiler to use unsigned for enum: Is there a way to make an enum unsigned in the C90 standard? (MISRA-C 2004 compliant)

Things I've Tried:

One workaround I found was to add a special enumerated variable that has all the other flags set. I can use that as a mask to reset flag A:

typedef enum {
     ....
     FLAGS_RESET_A  = (FLAGS_B | FLAGS_C | FLAGS_D) 
} flags_t

flag_t flags &= (FLAGS_RESET_A);  // Reset A 

This workaround is cumbersome. Any time I modify the flags type, such as adding a flag, I also have to remember to modify all the reset masks. I'm hoping there is a method that preserves the enum as a "single source of truth" for the flag definitions.

Another workaround is type casting to an unsigned integer, but that defeats the safety of using an enumerated type.

Luminaire
  • 334
  • 6
  • 11
  • 6
    Re “the safety of using an enumerated type”: The C standard does not provide much safety with enumerated types. Your compiler and compliance-checking tools might try, but consider that if `foo` is some enumeration constant, `~foo` is a generally not a value in the enumeration, so you are outside of type safety anyway, even if you resolve the signedness issue. – Eric Postpischil Jan 01 '22 at 19:39
  • 5
    This is probably why people usually use macros instead of enums for bitmasks. `#define FLAGS_A (1U << 0)` etc. – Nate Eldredge Jan 01 '22 at 19:46
  • 2
    On the other hand, I am pretty sure `~` is supposed to work on signed types, so this may be a bug or non-conformance in your compiler. (In principle the results might be strange if your compiler does something strange, like representing `1` with some binary value other than `0b000...0001`, but that seems unlikely.) – Nate Eldredge Jan 01 '22 at 19:49
  • @EricPostpischil I see, so maybe sticking my neck out for enums here is a dead end. – Luminaire Jan 02 '22 at 00:17
  • @NateEldredge Now that you brought that up, I tried using ~ on enum in OnlineGDB and the compiler didn't complain. So maybe this is only an issue for a few compilers. Macros sound like the lesser evil here. – Luminaire Jan 02 '22 at 00:18

0 Answers0