What is your procedure when switching over an enum where every enumeration is covered by a case? Ideally you\'d like the code to be future proof, how do you do that?
<First of all, I would always have a default
in a switch
statement. Even if there are no idiots around to cast int
egers to enum
s, there's always the possibility of memory corruption that the default
can help to catch. For what it's worth, the MISRA rules make the presence of a default a requirement.
Regarding what you do, that depends on the situation. If an exception can be handled in a good way, handle it. If it's a state variable in a non-critical part of code, consider silently resetting the state variable to the initial state and carrying on (possibly logging the error for future reference). If it is going to cause the entire program to crash in a really messy way, try to fall over gracefully or something. In short, it all depends on what you're switch
ing on and how bad an incorrect value would be.
Because it may help to know what the unexpected value of the enum was, write your own BADENUM(Enum) macro, along the lines of:
#define _STRIZE(x) _VAL(x)
#define _VAL(x) #x
extern void __attribute__ ((noreturn)) AssertFail(const char *Message);
#define ASSERT(Test) ((Test) ? (void)0 : AssertFail(__FILE__ ":" _STRIZE(__LINE__) " " #Test))
extern void __attribute__ ((noreturn)) BadEnum(const char *Message, const long unsigned Enum);
#define BADENUM(Enum) BadEnum(__FILE__ ":" _STRIZE(__LINE__), (u32)Enum))
As a further option: Avoid switching over enums.
As an additional remark (in addition to other responses) I'd like to note that even in C++ language with its relatively strict type-safety restrictions (at least compared to C), it is possible to generate a value of enum type that in general case might not match any of the enumerators, without using any "hacks".
If you have a enum type E
, you can legally do this
E e = E();
which will initialize e
with zero value. This is perfectly legal in C++, even if the declaration of E
does not include a enumeration constant that stands for 0
.
In other words, for any enum type E
, the expression E()
is well-formed and generates zero value of type E
, regardless of how E
is defined.
Note, that this loophole allows one to create a potentially "unexpected" enum value without using any "hacks", like a cast of an int
value to enum type you mentioned in your question.