#c
Вопрос:
Я работаю с предупреждениями компилятора в проекте, пытаясь очистить код, и одно предупреждение/ошибка, которая меня смутила unused-label
, — это предупреждение для следующего кода.
STATE(initialize)
В нем говорится, что метка «инициализировать» определена, но не используется. STATE
представляет собой #define
макрос, который выглядит следующим образом:
#define STATE(x) x: __TRACE__("enter", #x);
И __TRACE__
макрос выглядит следующим образом:
#define __TRACE__(y,x) dbg.printf(DebugIO::debug2,"FSM:" y "(" x ")n");
Обратите внимание, что я не писал этот код и просто работаю над проектом, пытаясь исправить как можно больше предупреждений. Но из того, что я могу сказать, initialize
метка передается туда __TRACE__
, где она используется в качестве аргумента для printf()
вызова.
Итак, почему же он не используется? Разве компилятор не рассматривает директивы препроцессора для использования переменных?
Как бы я это исправил?
Ответ №1:
из того, что я могу сказать,
initialize
метка передается туда__TRACE__
, где она используется в качестве аргумента дляprintf()
вызова.
Нет, на самом деле это не так. x
Параметр of STATE()
не совпадает с x
параметром of __TRACE__()
.
В инструкции STATE(initialize)
x
параметр является initialize
, поэтому x:
становится простым initialize:
(рассматриваемая метка), но #x
строит входное значение x
as "initialize"
в данном случае, поэтому STATE(initialize)
расширяется до этого:
initialize: __TRACE__("enter", "initialize");
А затем в __TRACE__
макросе y
параметр есть "enter"
и x
параметр есть "initialize"
, поэтому __TRACE__("enter", "initialize")
расширяется до этого:
dbg.printf(DebugIO::debug2,"FSM:" "enter" "(" "initialize" ")n");
И, наконец, строковые литералы, разделенные только пробелами, объединяются компилятором вместе, поэтому окончательный код STATE(initialize)
выглядит следующим образом:
initialize: dbg.printf(DebugIO::debug2,"FSM:enter(initialize)n");;
И поскольку нет никакого goto
или другого утверждения, ссылающегося на initialize
метку, именно поэтому вы получаете предупреждение об этом.
Как бы я это исправил?
Если goto initialize
где-то в коде нет фактического утверждения, я бы просто полностью избавился от ярлыка:
#define STATE(x) __TRACE__("enter", #x);
Комментарии:
1. Ах, мне было интересно, что делает оператор # в этом контексте, так как я не часто использую директивы препроцессора. Спасибо за объяснение.
2. При ближайшем рассмотрении прямо перед вызовом STATE() есть переход, который вызывает переход на метке инициализации. Не уверен, что это что-то сломает.
3. Тогда в этом случае метка не будет неиспользуемой, и компилятор не должен жаловаться на это. Похоже на ошибку компилятора.
4. В любом случае, я попросил старшего члена моей команды, и они сказали, чтобы он не трогал код FSM и просто подавил предупреждение.
Ответ №2:
Сама причина предупреждения заключается в том, что
x: TRACE...
представляет метку, с которой будет использоваться goto
. Это свидетельствует о том, что нет goto
необходимости инициализировать состояние (похоже, мы смотрим на реализацию FSM).
Вероятно, нет способа удалить это предупреждение без повторной работы фреймворка (например, добавления специального макроса состояния, который не определяет метку для состояний, в которые вы никогда не попадаете), но можно также просто отключить это конкретное предупреждение для проекта.
Комментарии:
1. Да, это реализация FSM, и да, прямо перед СОСТОЯНИЕМ есть вызов GOTO, который ссылается на метку инициализации. Есть ли способ, которым я могу подавить только этот экземпляр «неиспользуемой метки», не подавляя другие экземпляры?
Ответ №3:
Обратите внимание, что это __attribute__((unused))
можно использовать на этикетке.
Преобразование аргумента макроса в строку не считается «использованием» метки с тем же именем (помните, что метки в любом случае являются отдельным пространством имен от переменных, не говоря уже о аргументах макроса).
Использование унарного оператора (расширение GCC) amp;amp;
для получения адреса метки также может подавить предупреждение, но, как правило, вам следует избегать всего, что выглядит как динамика goto
, если вы действительно не знаете, что делаете. Поэтому предпочитайте версию атрибута.
Обратите также внимание, что __TRACE__
это зарезервированное имя, так как оно содержит 2 символа подчеркивания рядом друг с другом.
Комментарии:
1. Также можно использовать
[[maybe_unused]]
. MSVC по какой-то причине не принимает это, но GCC и Clang принимают.