2

I have a C function which uses an enum as parameter, like the example bellow:

typedef enum
{
  AB, 
  CD
} A;

void f(A input)
{
  // do something
}

int main(void)
{
   // do something
   f(-10);
   // do something
}

Is there a warning that I can enable for assigning an enum variable with a value out of the range of the enum?

S.S. Anne
  • 15,171
  • 8
  • 38
  • 76
Felipe GM
  • 129
  • 1
  • 8
  • 2
    Clang provides a warning with `-Wassign-enum`. – Eric Postpischil Jan 23 '20 at 14:40
  • thanks @EricPostpischil, but I am using GCC so this does not apply – Felipe GM Jan 23 '20 at 14:43
  • 1
    My spontaneus thought is that if you pass an invalid value in this situation, there's something SERIOUSLY wrong with your design... – klutt Jan 23 '20 at 14:57
  • it is an user API, and hence I cannot control what the user will do with it. Of course, I can control the parameter in the function body. I am looking for a way to prevent it at compilation level – Felipe GM Jan 23 '20 at 14:58

3 Answers3

9

There is an open bug for it in the GCC bug database. It seems that GCC does not contain such a feature yet. There is an option called -Wc++-compat which would complain - among myriad other things, about any integer being converted implicitly to an enum type.

A related feature has just landed into the GCC repository. In GCC trunk (but not in 9.2.1 which is the compiler of Ubuntu 19.10), there is a switch -Wenum-conversion, which would warn about the use of an unrelated enum value, but not a bare integer; i.e. with the code below it will warn about the latter function call, but not the former.:

typedef enum{ AB, CD } A;

typedef enum{ EF, GH } B;

void f(A input){
    (void)input;
}

int main(void){
    f(-10);
    f(GH);
}

The diagnostics from compiling with -Wenum-conversion would be

<source>: In function 'main':
<source>:18:6: warning: implicit conversion from 'enum <anonymous>' to 'A' [-Wenum-conversion]
   18 |    f(GH);
      |      ^~
2

Even if enum is a user defined type, it is translated by the compiler as a primitive, in my case int, you can check it using:

#include <stdio.h>

#define printHelloIfEnumIsInt(x) \
    _Generic(x, int: puts("Hello"));

typedef enum {
  AB, 
  CD
} A;

int main(void)
{
    printHelloIfEnumIsInt(AB);
    return 0;
}

returns:

Hello

so any value in the range of INT_MIN ... INT_MAX is allowed.

David Ranieri
  • 39,972
  • 7
  • 52
  • 94
  • exactly my point David! It is translated to integer, which shades the capture of the out of the range problem. I was wondering if there wasn't a flag to capture it before it happens – Felipe GM Jan 23 '20 at 14:55
0

I don't think there's any good way of doing it. But, provided that you do not use any = in your enum like enum foo {a=0, b=4}, you can do like this:

typedef enum{
  AB, 
  CD,
  A_max // Extra field that should be last
} A;

void f(A input){
    assert(input >= 0 && input < A_max);
    //  Do something
}

This works, because if no = is used, the first element will be zero, and all the following will add 1 for each of them.

klutt
  • 30,332
  • 17
  • 55
  • 95
  • yes klutt, at the function body one can assert the input and ensure it will be within range. I was wondering if GCC didn't have any prevention at compilation level, as G++ or Clang do – Felipe GM Jan 23 '20 at 15:15