14

Assuming that I have this:

enum { A = 0x2E, B = 0x23, C = 0x40 }

it's possible check if x is defined into enum?

I'm doing it manually: int isdef = (x == A || x == B || x == C); But I want to something more dynamic. GCC-extensions are welcome too.

Jack
  • 16,276
  • 55
  • 159
  • 284

7 Answers7

13

Not to the best of my knowledge. An enum in C is just a cleaner alternative to a series of

#define A 0x2E

statements.

If the enum is large and its values happen to be continuous, declare min/max constants and compare to those:

enum { E_MIN = 0x2E, A = 0x2E, B = 0x23, C = 0x40 ..., E_MAX=0x100};

if(x >= MIN && x <= MAX)
    ItsInEnum();
Seva Alekseyev
  • 59,826
  • 25
  • 160
  • 281
  • 4
    If values are discontinuous, you can put them in a constant array (sorted) and do a quick binary search to find if it's in there. – TJD Jun 14 '12 at 20:43
  • Since enums are compile-time constants, you could even design a perfect hash function and find the answer in *constant* time. – Jens Jun 14 '12 at 21:49
  • Hash calculation time might be comparable to that of comparison by hand. For enums, large-N behavior is not that relevant IMHO. – Seva Alekseyev Jun 14 '12 at 22:32
  • 3
    Thanks for your answer! `E_MIN` and `E_MAX` is a very good solution; but the values aren't continuos, so I can't use it. – Jack Jun 15 '12 at 14:46
  • 1
    Regarding your first statement, what is the equivalent of `#ifdef A` if `A` was defined in an enum? – Jeroen Ooms Dec 13 '14 at 09:00
  • There isn't one. Enum constants are identifiers, like variable and function names. If A is not defined and you try to use it, you'll get a compilation error. C doesn't easily admit checks for identifier validity. – Seva Alekseyev Dec 13 '14 at 20:08
12

This is kind of a modified version of your question, but depending on what you're doing, something like this might work:

enum {A,B,C};
const int E[] = {0x2E,0x23,0x40};
// Or:
// enum { A = 0x2E, B = 0x23, C = 0x40 };
// const int E[] = {A,B,C};

int isEnum(int x)
{
    for(int i=0; i<(sizeof(E)/sizeof(*E)); i++)
    {
        if(E[i] == x){ return 1; }
    }
    return 0;
}

int main(void)
{
    printf("Value of A: 0x%02x\n", E[A]);
    // Or:   
    // printf("Value of A: 0x%02x\n", A);

    printf("isEnum(0x2e): %s\n", isEnum(0x2e) ? "true" : "false");
    printf("isEnum(0x2f): %s\n", isEnum(0x2f) ? "true" : "false");
}

which outputs

Value of A: 0x2e
isEnum(0x2e): true
isEnum(0x2f): false

EDIT: TJD beat me to it, and his suggestion of using a sorted array and doing binary search would decrease your search time from n to log(n).

jedwards
  • 29,432
  • 3
  • 65
  • 92
12

The easiest way to do this is:


enum {
    MODE_A,
    MODE_B,
    MODE_C
};

int modeValid(int mode)
{
    int valid = 0;

    switch(mode) {
        case MODE_A:
        case MODE_B:
        case MODE_C:
            valid = 1;
    };

    return valid;
}

void setMode(int mode)
{
    if (modeValid(mode)) {
        // Blah, blah
    }
}

int main(void)
{
    setMode(1);   // Okay
    setMode(500); // Error
}
Luke Kowald
  • 121
  • 1
  • 2
8

To expand on the accepted answer, use X-macros to build your enum and array from the same data using the preprocessor.

/* Only need to define values here. */
#define ENUM_VALUES \
    X(A, 0x2E)  \
    X(B, 0x23)  \
    X(C, 0x40)

/* Preprocessor builds enum for you */
#define X(a, b) a = b,
    enum {
        ENUM_VALUES
    };
#undef X

/* Preprocessor builds array for you */
#define X(a, b) a,
    const int E[] = {
        ENUM_VALUES
    };
#undef X

/* Copied from accepted answer */
int isEnum(int x)
{
    for(int i=0; i<sizeof(E);i++)
    {
        if(E[i] == x){ return 1; }
    }
    return 0;
}
AaronDanielson
  • 2,230
  • 28
  • 29
  • 1
    Shouldn't t be `(sizeof(E)/sizeof(*E))` instead of `sizeof(E)`? – frarugi87 May 25 '19 at 07:00
  • @frarugi87, thanks, good catch! I see the part I copied from that other answer has since been edited to include the snippet you're referencing here. Yes, you're right. – AaronDanielson May 28 '19 at 17:06
1

An enum is essentially the same thing as using macros to define constants, except that the enum wraps a set of associated constants up into a data type. This makes your code more self-documenting, but doesn't really provide any additional functionality.

If you venture outside the realm of standard C, some compilers can do extra things with enum that they can't do with macros. Some debuggers will map enum variables back to their name instead of showing their value. Also, some compilers provide the ability to add run-time checks for things like out-of-bounds enum values. This is essentially the same as the code you show, only the compiler adds it automatically. With GreenHills' C compiler, this feature is enabled with the -check=assignbound compiler option. I'm not sure if gcc has something like this built-in or not. What compiler are you using?

bta
  • 43,959
  • 6
  • 69
  • 99
1

Here is another possible solution:

#include <stdio.h>
#include <stdint.h>

typedef enum {
  VALUE_1 = 0x01,
  VALUE_2 = 0x03,
  VALUE_3 = 0x0A
} values_e;

int main(void)
{
  int a = 0;
  values_e vlr;

  for (int i = 0; i < 10; i++) {
    scanf("%d", &a);

    vlr = (values_e)a;
    switch (vlr) {
      case VALUE_1:
        printf("do ... value 1:\r\n");
        break;

      case VALUE_2:
        printf("do ... value 2:\r\n");
        break;

      case VALUE_3:
        printf("do ... value 3:\r\n");
        break;

      default:
        printf("ops...\r\n");
    }
  }
}
0

As already pointed out, it is not possible to check if an enum is defined by directly referring to an enum member. However, there is a very simple shortcut: define a unique identifier associated with each enumerated type. Then, when you want to check if an element of the enumeration exists, you can simply check if the associated identifier is defined:

//Header File:
typedef enum 
{
   ENUM_ELEMENT_1 = 0,
   ENUM_ELEMENT_2 = 1,
   ENUM_ELEMENT_3 = 2,
   ENUM_ELEMENT_MAX
} eEnumElement;

#define ENUM_ELEMENT_DEFINED  1

...

//Source file:
void TaskOperateOnEnums(void) 
{
   #if defined(ENUM_ELEMENT_DEFINED)
   eEnumElement Test = ENUM_ELEMENT_1;
   ...
   #endif
}