2

I'm reviewing a lot of code that looks like this

typedef enum {
    OPTION1
    OPTION2
} option_t

...

void a_function(option_t option){
    if(option == OPTION1){
        ...
    } else if(option == OPTION2){
        ...
    } else {
        // report an error!
        // can we ever get here?
    }
}

My question is, is the else clause that reports the error needed? It seems to me, that as option is of type option_t, an enum that only has 2 possibilities, it should not be possible for option to have any value except OPTION1 and OPTION2, so it should be impossible for the else clause to ever be executed.

ACarter
  • 5,688
  • 9
  • 39
  • 56
  • What would prevent a caller from passing `-1` or `4711` to your function? – Gerhardh Feb 22 '23 at 11:45
  • @Gerhardh idk the compiler? Feels like `option` being an `option_t` instead of `int` should prevent that? – ACarter Feb 22 '23 at 11:46
  • 2
    An `enum` basically simply defines names for constant values. It does not specify a specific integer type (signed or unsigned, short or long, ...) for them or put some limits in place. – Gerhardh Feb 22 '23 at 11:48
  • 1
    Re “Can a C typedef enum take a value greater than the number of elements in the enum?”: That is not the question you want to ask; `enum foo { a = 12 }` has a value greater than the number of its named members. – Eric Postpischil Feb 22 '23 at 13:02

2 Answers2

6

Enums do not have much in the way of type safety and are generally broken by design type-wise (as of today's date, upcoming C23 will change many C language defects). In your example OPTION1 is of type int and option_t is of some integer type large enough to fit all values in the enumeration list, not necessarily int.

My question is, is the else clause that reports the error needed?

It is what's known as "defensive programming". In theory the enum should not have any other values. In practice, nothing is stopping you from assigning any integer value to it. Or in case of memory corruption bugs, nothing is stopping the bug from changing it to another value either.

So it depends on your requirements. For commerical/hobbyist/PC requirements, the else is probably not required. For safety-related, mission-critical or similar software (MISRA C compliance for example), the else is required and good practice.

Related post: How to create type safe enums?

Lundin
  • 195,001
  • 40
  • 254
  • 396
4

The C standard is not explicit about this, but each enumerated type is actually some regular integer type. Although C 2018 6.12.5 16 says “… Each distinct enumeration constitutes a different enumerated type”, 6.7.2.2 4 says “Each enumerated type shall be compatible with char, a signed integer type, or an unsigned integer type. The choice of type is implementation-defined, but shall be capable of representing the values of all the members of the enumeration…”

Neither of those is clear about what values can be represented in the enumerated type or whether the behavior is defined for values not among the named values of the enumeration—saying two types are compatible is not an assertion that all the values of one type are representable by the other type.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312