Предупреждение о неиспользуемой метке G для макроса препроцессора

#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 принимают.