GCC включает enum, сохраняет пропущенное предупреждение, но использует значение по умолчанию - PullRequest
15 голосов
/ 23 марта 2011

Используя GCC, если вы switch для значения enum и в одном из перечислений отсутствует оператор case, будет выдано предупреждение.Когда вы добавляете элемент default, предупреждение больше не будет выводиться, что имеет смысл в общем случае.

Есть ли способ использовать оператор default и при этом иметь предупреждение, если не всеenum значения покрыты?Так как моя функция может иметь дело с нечистым вводом, я бы хотел охватить общий случай, но все равно получать предупреждения компилятора об отсутствии регистра enum.

В настоящее время я в конечном итоге назначаю значение по умолчанию после оператора switch.

Ответы [ 5 ]

10 голосов
/ 23 марта 2011

-Wswitch-enum , но, к несчастью, это поддерживается только в самой последней версии.

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

3 голосов
/ 01 ноября 2015

Прочитав ссылку из «David Rodríguez - dribeas», я подумал, что было бы полезно обобщить перечисленные там варианты.

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

Вариант 1: Предупреждения для всех, пометьте некоторые как тихие

Сначала добавьте -Wswitch-enum к вашим флагам компилятора, чтобы все операторы switch, даже те, которые имеют предложение default,будут генерироваться предупреждения, если перечисление не обрабатывается.

Затем, для тех операторов switch, где вы хотите, чтобы дело default заботилось о вещах и не хотело видеть предупреждения, оберните switch оператор, подобный следующему:

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wswitch-enum"

switch () {
    ...
}

#pragma GCC diagnostic pop

Это временно отключит флаг -Wswitch-enum (скрывая предупреждения о пропущенных регистрах перечислений) только для этого оператора.

Вариант 2: Только шarn, если для этого установлен флажок

Поскольку поведение GCC по умолчанию состоит в том, чтобы скрывать предупреждения при наличии предложения default, флаги компилятора для этой опции изменять не нужно.

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

#pragma GCC diagnostic push
#pragma GCC diagnostic warning "-Wswitch-enum"

switch () {
    ...
}

#pragma GCC diagnostic pop

Это временноактивирует флаг -Wswitch-enum между строками push и pop, в результате чего сообщения о пропущенных случаях перечисления отображаются даже при наличии предложения default.Вы можете изменить слово warning на error, если хотите, чтобы компиляция не удалась в пропущенном случае.

1 голос
/ 23 марта 2011

Я бы сказал, что проблема больше на уровне enum.

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

Для проверки ввода, простое решение , которое я использую, заключается в создании перечисления с помощью макроса, который также автоматически генерирует преобразование функций: из / в string, от int (или еще чего-нибудь).

Например:

DEFINE_ENUM_DETAILED(SomeEnum, int, (Foo, 0, "Foo")(Bar, 1, "Bar"));

Может генерировать:

struct SomeEnum {
  enum { Foo = 0, Bar = 1 } type;

  type FromString(std::string const& s) {
    if (s == "Foo") { return Foo; }
    if (s == "Bar") { return Bar; }
    assert(0 && "SomeEnum::FromString - unknown value");
  }

  std::string ToString(type e) {
    switch(e) {
    case Foo: return "Foo";
    case Bar: return "Bar";
    }
  }

  type FromIntegral(int i) {
    switch(i) {
    case Foo: return Foo;
    case Bar: return Bar;
    }
    assert(0 && "SomeEnum::FromIntegral- unknown value");
  }
};

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

Другим решением будет использование сценария для генерации исходного кода из альтернативного файла.

РЕДАКТИРОВАТЬ: Наличие и проверка выключателя

Простой ответ (как я и сделал выше) - позволить программе вытекать из коммутатора вместо использования предложения по умолчанию. Это возможно, если нормальный поток (при попадании в case) не выпадает из переключателя.

switch(event) {
case Foo: {
  // bla
  return 0;
}
case Bar: {
  return 0;
}
}

unreachable("should never have got there");
1 голос
/ 23 марта 2011

К сожалению, на сегодняшний день ни gcc, ни llvm не могут обнаружить, что вы не сравниваете все значения enum в switch, если включить переключатель default.

0 голосов
/ 23 марта 2011

Одной из причин может быть то, что вы должны быть в состоянии писать код без предупреждений, не ломая спину.Если, например, у вас есть перечисление со 100 константами, то вам нужно будет перечислить каждый из них в каждом операторе switch, даже если вам нужно только осмотреть несколько из них, если предупреждение должно работать так, как вы предлагали.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...