Подтвердить что ты не робот

Как проверить, действительна ли переменная enum?

У меня есть перечисление:

enum myenum{
  typeA,
  typeB,
  typeC
} myenum_t;

Затем функции должны вызываться с параметром enum:

int myfunction(myenum_t param1)
{
  switch(param1)
  {
    case typeA:
    case typeB:
    case typeC:
      //do the work
      break;

    default:
      printf("Invalid parameter");
  }
  return 0;
}

Но, поскольку myenum_t растет с большим количеством значений, myfunction не кажется таким изящным.

Есть ли лучший способ проверить, является ли перечисление действительным или нет?

4b9b3361

Ответ 1

Общим соглашением для этого является сделать что-то вроде этого:

typedef enum {
  typeA,
  typeB,
  typeC,
  num_types
} myenum_t;

Затем вы можете проверить (t < num_types).

Если впоследствии добавить дополнительные перечисления, например

typedef enum {
  typeA,
  typeB,
  typeC,
  typeD,
  typeE,
  num_types
} myenum_t;

то num_types автоматически обновляется, и ваш код проверки ошибок не нуждается в изменении.

Ответ 2

Вы можете использовать побитовое перечисление:

enum myEnum {
    typeA = 1 << 0;
    typeB = 1 << 1;
    typeC = 1 << 2;
}

int myFunction(myEnum arg1)
{
    int checkVal = typeA | typeB | typeC;

    if (checkVal & arg1)
    {
        // do work here;
    }
    else
    {
        printf("invalid argument!");
    }

    return 0;
}

Извините, кажется, я неправильно прочитал этот вопрос.

Кажется, что вы хотите, чтобы определить, есть ли у вас надлежащее значение, а не какой-либо случайный недопустимый параметр. В этом случае наиболее логичным вариантом является следующее:

if (arg1 < typeA || arg1 > typeC)
    printf("invalid argument");

Это, конечно, предполагает, что вы не задаете ручные значения для вашего перечисления, что довольно редко, если не использовать побитовые перечисления.

Ответ 3

Да.

Пусть компилятор выполнит свою работу, не применяйте int к типу enum, и вам должно быть хорошо.

Ответ 4

Один трюк, который я использовал в прошлом:

enum foo {FIRST_FOO, BAR, BLETCH, BLURGA, BLAH, LAST_FOO};

а затем проверьте, соответствует ли ваше значение > FIRST_FOO && < LAST_FOO 1.

Конечно, это предполагает, что между вашими значениями перечисления нет пробелов.

В противном случае нет, нет хорошего способа делать то, что вы просите (по крайней мере, на C).


1 Из последнего онлайн C Language Standard:
6.7.2.2 Спецификаторы перечисления
...
3 Идентификаторы в списке перечислителей объявляются как константы, имеющие тип int и может появляться везде, где это разрешено. 109) Перечислитель с = определяет его константа перечисления как значение постоянного выражения. Если первый счетчик no =, значение его константы перечисления 0. Каждый последующий перечислитель без = определяет его константу перечисления как значение константного выражения, полученного добавив 1 к значению предыдущей константы перечисления. (Использование счетчиков с = может создавать константы перечисления со значениями, которые дублируют другие значения в одном и том же перечисление.) Перечисления перечисления также известны как его члены.

Ответ 5

Разве вы не можете сделать что-то вроде

enum myEnum {typeA,typeB, typeC};

int myFunction (myEnum arg1) {
    if (arg1 >= typeA && arg1 <= typeC) {
        // do work here
    } else {
        printf("invalid argument!");
    }
    return 0;
}

Ответ 6

К сожалению, нет простого способа сделать это на уровне языка (по крайней мере, с C), вам просто нужно убедиться, что вы используете только переменные, определенные с помощью enum.

Хотя вы можете включить одно из следующих предупреждений компилятора вместе с -Werror:

  • -Wswitch
  • -Wswitch-default
  • -Wswitch-enum

Это приводит к сбою сборки, если одно из перечислений пропущено внутри коммутатора.

Ответ 7

Перечисления в С++ уже имеют более сильные типы, чем в C.

Возьмите следующую простую программу:

#include <iostream>

enum E
{
    A,
    B 
};

void f(E e)
{
}

int main()
{
    f(1);
}

Используя компилятор GCC, я получу эту ошибку:

enum.cpp: In function ‘int main()’:
enum.cpp:15: error: invalid conversion from ‘int’ to ‘E’
enum.cpp:15: error:   initializing argument 1 of ‘void f(E)’

Итак, как вы видите, элементы перечисления уже проверены.

Если вы хотите еще более сильную проверку типов и иметь компилятор С++ 11, вы можете использовать еще более эффективную проверку типов для перечислений, см. http://en.wikipedia.org/wiki/C%2B%2B11#Strongly_typed_enumerations.