Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to protect enum assignment

I want to prevent invalid value enum assignment. I know if i even assign value that is not in enum it will work. Example:

enum example_enum
{
    ENUM_VAL0,
    ENUM_VAL1,
    ENUM_VAL2,
    ENUM_VAL3
};

void example_function(void)
{
  enum example_enum the_enum = ENUM_VAL3; // correct
  the_enum = 41; // will work
  the_enum = 0xBADA55; // also will work
  bar(the_enum); // this function assumes that input parameter is correct
}

Is there easy, efficient way to check if assignment to enum is correct? I could test value by function

void foo(enum example_enum the_enum)
{
  if (!is_enum(the_enum))
    return;

  // do something with valid enum
}

I could resolve this in following way:

static int e_values[] = { ENUM_VAL0, ENUM_VAL1, ENUM_VAL2, ENUM_VAL3 };
int is_enum(int input)
{
  for (int i=0;i<4;i++)
    if (e_values[i] == input)
      return 1;
  return 0;
}

For me, my solution is inefficient, how can i write this if i have more enums and more values in enums?

like image 863
shjeff Avatar asked Dec 02 '25 06:12

shjeff


2 Answers

As long as the enum is continuous one can do something like this:

static int e_values[] = { ENUM_VAL0, ENUM_VAL1, ENUM_VAL2, ENUM_VAL3, ENUM_VAL_COUNT };

int is_enum(int input) { return 0 <= input && input < ENUM_VAL_COUNT; }

Another alternative is to not validate the enum value beforehand, but error out once the code detects an invalid value:

switch(input) {
    case ENUM_VAL0: ... break;
    case ENUM_VAL1: ... break;
    ...
    default:
        assert(0 && "broken enum"); 
        break;
} 

But there is no way to enforce that the enum value doesn't go out of the range at all in C. The best you can do if you want to secure the enum against fiddling is to hide the value away in a struct and then have functions to manipulate the struct. The function and struct implementation can be hidden away from the user via a forward declaration in the .h file and the implementation in the .c file:

struct example_t {
     enum example_enum value;
}

void example_set_val0(example_t* v) { v->value = ENUM_VAL0; }
like image 51
Grumbel Avatar answered Dec 03 '25 21:12

Grumbel


There is no way of warning about assigning integers that fit into the enum.

Enumerators in C are synonyms for integer types. Assuming the type chosen for enum example_enum is int, then your code is identical to:

void example_function(void)
{
  int the_enum = ENUM_VAL3; // correct
  the_enum = 12345; // will work
  bar(the_enum); // this function assumes that input parameter is correct
}

void foo(int the_enum)
{
  if (!is_enum(the_enum))
    return;
  // do something with valid enum
}

You could use structures, but even that can be circumvented:

struct example_enum_struct e = { 12345 };
e.value = 23456;

Basically if you want to restrict a type to specific values, you will need to perform checks.

like image 29
2501 Avatar answered Dec 03 '25 20:12

2501



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!