~lobisquit/better_c_enums

3d3ffbb3 — Enrico Lovisotto 4 months ago
Updated LICENSE to MIT
5aa326bb — Enrico Lovisotto 4 months ago
Added dynamic enum, via mutable array of struct
d57fd62e — Enrico Lovisotto 4 months ago
Added example of better enum in C, done using structs

refs

main
browse  log 

clone

read-only
https://git.sr.ht/~lobisquit/better_c_enums
read/write
git@git.sr.ht:~lobisquit/better_c_enums

You can also use your local clone with git send-email.

#C enums are bad

Due to being simple alias for integers, C enums are not type-safe. This means that an enum could be initialized using another one without the compiler (at least GCC) complaining.

Moreover, parsing from integer and conversion to string is cumbersome. It requires, in the worst case of non-consecutive enum values, a switch case for each operation. These switch-case must be kept aligned with the enum variants, especially if a new one is added.

#A solution

Using struct instances as enum variants could mitigate the issues of enum, while keeping a lot of their convenience.

A struct like this could be assigned an integer and a string representation. This way the two are always aligned and the variant to string conversion is simplified.

typedef struct {
  int num;
  const char *const label;
} BAR_OPTION;

The collection of variants could be stored in an array, like this. The number of elements then comes for free and it is updated along with the array.

const BAR_OPTION BAR_OPTION_A = {BAR_OPTION_A_raw, "BAR: OPTION_A"};
const BAR_OPTION BAR_OPTION_B = {BAR_OPTION_B_raw, "BAR: OPTION_B"};
const BAR_OPTION BAR_OPTION_C = {BAR_OPTION_C_raw, "BAR: OPTION_C"};

static const BAR_OPTION *const BAR_OPTIONS[] = {&BAR_OPTION_A, &BAR_OPTION_B, &BAR_OPTION_C};

const int NUMBER_OF_BAR_OPTIONS = sizeof(BAR_OPTIONS) / sizeof(BAR_OPTIONS[0]);

#Dynamic variants

As an additional point, the BAR_OPTIONS array could be made mutable, to allow registering more variants dynamically.

With respect to the static approach, only these two functions are added.

bool BAZ_OPTION_register(const BAZ_OPTION *const new_choice);
bool BAZ_OPTION_unregister(const BAZ_OPTION *const new_choice);

#Conclusion

Overall, this struct-as-enum strategy offers interesting advantages at the cost of a slightly higher number of rows.