C: как мне не скомпилировать, когда -Wswitch выключен?

Если я хочу мой switch(an_enum) Заявление будет сообщено, когда он пропускает дело перечисления, я могу включить -Wswitch флаг компилятора ( на gcc).

enum E { e1, e2, e3 };

...
switch(e) {
  case e1: ...
  case e2: ...
  // NO default: checked by -Wswitch and -Werror
}

Хорошо работает: "ошибка: значение перечисления 'e3' не обработано в switch [-Werror=switch]"

Но теперь правильность моего кода зависит от используемых флагов компилятора, что довольно хрупко.

Что-то вроде этого:

switch(e) __attribute__((exhaustive))
{
  ...
}

Есть ли способ, которым я могу заставить этот кусок кода потерпеть неудачу, если -Wswitch флаг выключен? Или временно включить его в коде?

2 ответа

Решение

Надежное и портативное решение - добавить default ярлык к вашему switch заявление. Это может сделать:

default:
    assert(0);
    abort();

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

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

#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic error "-Wswitch"
#endif /* __GNUC__ */

switch (e)
{
…
}

#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif /* __GNUC__ */

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

Если вы никогда не используете компилятор, отличный от GCC (или, возможно, Clang), вы можете опустить __GNUC__ тесты. Однако компиляторы на других платформах (например, IBM XLC 13.1.3 в AIX 7.2) жалуются на специфические для GCC прагмы, хотя стандарт C говорит, что не должен. Вы платите свои деньги и выбираете.

Вы можете использовать ignore или же warning вместо error для достижения других эффектов, если вы предпочитаете.

Вы также можете отметить, что -Wswitch опция является одним из предупреждений, включенных -Wall - и если вы компилируете с GCC, вы всегда должны использовать -Wall (а также -Wextra а также -Werror), поэтому вы никогда не должны сталкиваться с проблемами.

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

Предполагая, что перечисление содержит только соседние числа, как в вашем примере, вы можете "развернуть" оператор switch, заменив его таблицей указателей на функции, что является довольно распространенной практикой. Таблица указателей на функции была бы чисто стандартной C. Пример:

typedef enum 
{ 
  e1, 
  e2, 
  e3,
  eN  // enum counter
} e_t;

typedef void e_func_t (void);

e_func_t* const do_stuff [] =   // array of functions of type void f(void);
{
  e1_stuff, 
  e2_stuff,
  e3_stuff,
};

// force compilation error if missing a "case statement":
_Static_assert(sizeof(do_stuff)/sizeof(*do_stuff) == eN, 
               "Function pointer table incomplete.");

Затем вы можете заменить весь переключатель следующим образом:

if(e < e1 || e >= eN)
{  
  /* handle errors or "default" here */ 
}
else
{
  do_stuff[e]();
}
Другие вопросы по тегам