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]();
}