2012-06-14 5 views
9

Если предположить, что у меня есть это:Проверьте, определено ли значение в C-перечислении?

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

это можно проверить, если x определяется в enum?

Я делаю это вручную: int isdef = (x == A || x == B || x == C); Но я хочу что-то более динамичное. GCC-extensions тоже приветствуются.

+1

нет, вы, вероятно, нужно использовать что-то иначе как набор <> –

+1

@AndersK: что такое 'set <>'? – Jack

ответ

9

Это вид модифицированной версии вашего вопроса, но в зависимости от того, что «повторно делать, что-то подобное может работать:

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"); 
} 

, который выводит

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

EDIT: TJD избил меня, и его предложение использовать отсортированный массив и выполнить двоичный поиск уменьшит время поиска от n до log (n).

+1

+1. Я бы также сделал x-macro для создания как enum, так и E [] - нет необходимости вручную синхронизировать между этими двумя структурами данных. –

13

Не в меру я знаю. Перечисление в C является просто более чистой альтернативой серии

#define A 0x2E 

заявления.

Если перечисление велико и его значения, оказывается непрерывным, объявите мин/макс константы и сравните эти:

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

if(x >= MIN && x <= MAX) 
    ItsInEnum(); 
+3

Если значения прерывистые, вы можете поместить их в постоянный массив (отсортированный) и выполнить быстрый бинарный поиск, чтобы найти, находится ли он там. – TJD

+0

Поскольку перечисления являются константами времени компиляции, вы даже можете создать идеальную хеш-функцию и найти ответ в * постоянном * времени. – Jens

+0

Время вычисления хеширования может быть сопоставимо с временем сравнения. Для перечислений поведение большого N не соответствует соответствующим IMHO. –

1

enum по существу то же самое, что использование макросов для определения констант, за исключением того, что enum обертывает набор связанных констант в тип данных. Это делает ваш код более самодокументированным, но на самом деле не предоставляет никаких дополнительных функций.

Если вы выходите за пределы стандарта C, некоторые компиляторы могут делать дополнительные вещи с помощью enum, что они не могут делать с макросами. Некоторые отладчики будут отображать enum переменные обратно к их имени, а не показывать их значение. Кроме того, некоторые компиляторы предоставляют возможность добавлять проверки во время выполнения таких вещей, как значения вне диапазона enum. Это по сути то же самое, что и код, который вы показываете, только компилятор автоматически добавляет его. С компилятором GreenHills 'C эта функция включена с параметром компилятора -check=assignbound. Я не уверен, что у gcc есть что-то вроде этого встроенного или нет. Какой компилятор вы используете?

4

Чтобы расширить принятый ответ, используйте X-макросы для создания вашего перечисления и массива из одних и тех же данных с помощью препроцессора.

/* 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; 
} 
4

Самый простой способ сделать это:


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 
} 
0

Как уже отмечалось, это не представляется возможным проверить, если перечисление определяется непосредственно со ссылкой на члена перечисления. Однако есть очень простой ярлык: определите уникальный идентификатор, связанный с каждым перечисляемым типом.Затем, когда вы хотите проверить, если элемент перечисления существует, то вы можете просто проверить, если ассоциированный идентификатор определяется:

//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 
} 
Смежные вопросы