Как проверить допустимость переменной enum? - PullRequest
12 голосов
/ 06 февраля 2012

У меня есть 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 не кажутся такими элегантными.

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

Ответы [ 7 ]

18 голосов
/ 06 февраля 2012

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

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 автоматически обновляется, и ваш код проверки ошибок не нужно менять.

5 голосов
/ 06 февраля 2012

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

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

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

4 голосов
/ 06 февраля 2012

Да.

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

1 голос
/ 06 февраля 2012

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

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

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

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

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


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

Перечисления в C ++ уже имеют более строгие типы, чем в 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)’

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

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

0 голосов
/ 06 февраля 2012

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

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

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

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

0 голосов
/ 06 февраля 2012

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

enum myEnum {typeA,typeB, typeC};

int myFunction (myEnum arg1) {
    if (arg1 >= typeA && arg1 <= typeC) {
        // do work here
    } else {
        printf("invalid argument!");
    }
    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...