Подтвердить что ты не робот

Как отключить предупреждения GCC для нескольких строк кода

В Visual C++ можно использовать #pragma warning (disable:...). Также я обнаружил, что в GCC вы можете переопределить флаги компилятора файлов. Как я могу сделать это для "следующей строки", или с семантикой push/pop вокруг областей кода, используя GCC?

4b9b3361

Ответ 1

Похоже, что это можно сделать. Я не могу определить версию GCC, что она была добавлена, но это было до июня 2010 года.

Вот пример:

#pragma GCC diagnostic error "-Wuninitialized"
    foo(a);         /* error is given for this one */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wuninitialized"
    foo(b);         /* no diagnostic for this one */
#pragma GCC diagnostic pop
    foo(c);         /* error is given for this one */
#pragma GCC diagnostic pop
    foo(d);         /* depends on command line options */

Ответ 2

Чтобы отключить все, это пример временно отключения предупреждения:

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-result"
    write(foo, bar, baz);
#pragma GCC diagnostic pop

Более подробную информацию можно найти в документации GCC по диагностическим прагмам.

Ответ 3

TL; DR: если это работает, избегайте или используйте спецификаторы, такие как __attribute__, иначе _Pragma.

Это короткая версия моей статьи в блоге " Подавление предупреждений в GCC и Clang".

Рассмотрим следующий Makefile

CPPFLAGS:=-std=c11 -W -Wall -pedantic -Werror

.PHONY: all
all: puts

для построения следующего исходного кода puts.c

#include <stdio.h>

int main(int argc, const char *argv[])
{
    while (*++argv) puts(*argv);
    return 0;
}

Он не скомпилируется, потому что argc не используется, а настройки хардкорные (-W -Wall -pedantic -Werror).

Есть 5 вещей, которые вы можете сделать:

  • Улучшите исходный код, если это возможно
  • Используйте спецификатор объявления, например __attribute__
  • Используйте _Pragma
  • Используйте #pragma
  • Используйте параметр командной строки.

Улучшение источника

Первая попытка должна проверять, можно ли улучшить исходный код, чтобы избавиться от предупреждения. В этом случае мы не хотим менять алгоритм только из-за этого, так как argc избыточен с !*argv (NULL после последнего элемента).

Использование спецификатора объявления, например __attribute__

#include <stdio.h>

int main(__attribute__((unused)) int argc, const char *argv[])
{
    while (*++argv) puts(*argv);
    return 0;
}

Если вам повезет, стандарт предоставляет спецификатор для вашей ситуации, например _Noreturn.

__attribute__ является проприетарным расширением GCC (поддерживается Clang и некоторыми другими компиляторами, такими как armcc) и не будет понято многими другими компиляторами. Поместите __attribute__((unused)) внутри макроса, если вы хотите переносимый код.

_Pragma оператор

_Pragma может использоваться как альтернатива #pragma.

#include <stdio.h>

_Pragma("GCC diagnostic push")
_Pragma("GCC diagnostic ignored \"-Wunused-parameter\"")

int main(int argc, const char *argv[])
{
    while (*++argv) puts(*argv);
    return 0;
}
_Pragma("GCC diagnostic pop") \

Основное преимущество оператора _Pragma заключается в том, что вы можете поместить его в макросы, что невозможно с помощью директивы #pragma.

Недостаток: это почти тактическое ядерное оружие, поскольку оно работает на основе строк, а не на основе объявлений.

Оператор _Pragma был введен в C99.

директива #pragma.

Мы могли бы изменить исходный код, чтобы отключить предупреждение для области кода, обычно всей функции:

#include <stdio.h>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
int main(int argc, const char *argv[])
{
    while (*++argc) puts(*argv);
    return 0;
}
#pragma GCC diagnostic pop

Недостаток: это почти тактическое ядерное оружие, поскольку оно работает на основе строк, а не на основе объявлений.

Обратите внимание, что подобный синтаксис существует в Clang.

Подавление предупреждения в командной строке для одного файла

Мы можем добавить следующую строку в Makefile чтобы отключить предупреждение специально для пут:

CPPFLAGS:=-std=c11 -W -Wall -pedantic -Werror

.PHONY: all
all: puts

puts.o: CPPFLAGS+=-Wno-unused-parameter

Это, вероятно, не хочет, чтобы вы хотели в вашем конкретном случае, но это может помочь другим чтения, которые находятся в подобных ситуациях.

Ответ 4

#pragma GCC diagnostic ignored "-Wformat"

Замените "-Wformat" на имя вашего предупреждающего флага.

AFAIK не существует возможности использовать семантику push/pop для этой опции.

Ответ 5

#define DIAG_STR(s) #s
#define DIAG_JOINSTR(x,y) DIAG_STR(x ## y)
#ifdef _MSC_VER
#define DIAG_DO_PRAGMA(x) __pragma (#x)
#define DIAG_PRAGMA(compiler,x) DIAG_DO_PRAGMA(warning(x))
#else
#define DIAG_DO_PRAGMA(x) _Pragma (#x)
#define DIAG_PRAGMA(compiler,x) DIAG_DO_PRAGMA(compiler diagnostic x)
#endif
#if defined(__clang__)
# define DISABLE_WARNING(gcc_unused,clang_option,msvc_unused) DIAG_PRAGMA(clang,push) DIAG_PRAGMA(clang,ignored DIAG_JOINSTR(-W,clang_option))
# define ENABLE_WARNING(gcc_unused,clang_option,msvc_unused) DIAG_PRAGMA(clang,pop)
#elif defined(_MSC_VER)
# define DISABLE_WARNING(gcc_unused,clang_unused,msvc_errorcode) DIAG_PRAGMA(msvc,push) DIAG_DO_PRAGMA(warning(disable:##msvc_errorcode))
# define ENABLE_WARNING(gcc_unused,clang_unused,msvc_errorcode) DIAG_PRAGMA(msvc,pop)
#elif defined(__GNUC__)
#if ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406
# define DISABLE_WARNING(gcc_option,clang_unused,msvc_unused) DIAG_PRAGMA(GCC,push) DIAG_PRAGMA(GCC,ignored DIAG_JOINSTR(-W,gcc_option))
# define ENABLE_WARNING(gcc_option,clang_unused,msvc_unused) DIAG_PRAGMA(GCC,pop)
#else
# define DISABLE_WARNING(gcc_option,clang_unused,msvc_unused) DIAG_PRAGMA(GCC,ignored DIAG_JOINSTR(-W,gcc_option))
# define ENABLE_WARNING(gcc_option,clang_option,msvc_unused) DIAG_PRAGMA(GCC,warning DIAG_JOINSTR(-W,gcc_option))
#endif
#endif

Это должно сделать трюк для gcc, clang и msvc

Может вызываться с помощью:

DISABLE_WARNING(unused-variable,unused-variable,42)
[.... some code with warnings in here ....]
ENABLE_WARNING(unused-variable,unused-variable,42)

см. https://gcc.gnu.org/onlinedocs/cpp/Pragmas.html, http://clang.llvm.org/docs/UsersManual.html#controlling-diagnostics-via-pragmas и https://msdn.microsoft.com/de-DE/library/d9x1s805.aspx для более подробной информации

Вам понадобится, по крайней мере, версия 4.02, чтобы использовать такие прагмы для gcc, не уверены в msvc и говорить о версиях.

Похоже, что обработка pop-pragma для gcc немного нарушена. Если вы снова включите предупреждение, вы все равно получите предупреждение для блока, который находится внутри блока DISABLE_WARNING/ENABLE_WARNING. Для некоторых версий gcc он работает, для некоторых это не так.

Ответ 6

У меня была такая же проблема с внешними библиотеками, как заголовки ROS. Мне нравится использовать следующие параметры в CMakeLists.txt для более строгой компиляции:

set(CMAKE_CXX_FLAGS "-std=c++0x -Wall -Wextra -Wstrict-aliasing -pedantic -Werror -Wunreachable-code ${CMAKE_CXX_FLAGS}")

Однако это приводит к возникновению всех видов педантичных ошибок во внешних библиотеках. Решение состоит в том, чтобы отключить все педантичные предупреждения перед включением внешних библиотек и повторным включением:

//save compiler switches
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"

//Bad headers with problem goes here
#include <ros/ros.h>
#include <sensor_msgs/LaserScan.h>

//restore compiler switches
#pragma GCC diagnostic pop

Ответ 7

Вместо того, чтобы замалчивать предупреждения, стиль gcc обычно использует либо стандартные конструкторы C, либо расширение __attribute__, чтобы больше рассказать компилятору о ваших намерениях. Например, предупреждение о присваивании, которое используется как условие, подавляется путем помещения задания в круглые скобки, то есть if ((p=malloc(cnt))) вместо if (p=malloc(cnt)). Предупреждения о неиспользуемых аргументах функции могут быть подавлены с помощью некоторого нечетного __attribute__, который я никогда не запомню, или путем самоопределения и т.д. Но обычно я предпочитаю просто глобально отключать любую опцию предупреждения, которая генерирует предупреждения для вещей, которые будут возникать в правильном коде.

Ответ 8

Для тех, кто нашел эту страницу в поиске способа сделать это в IAR, попробуйте следующее:

#pragma diag_suppress=Pe177
void foo1( void )
{
   /* The following line of code would normally provoke diagnostic 
      message #177-D: variable "x" was declared but never referenced.
      Instead, we have suppressed this warning throughout the entire 
      scope of foo1(). 
   */
   int x;
}
#pragma diag_default=Pe177

См. http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0472m/chr1359124244797.html для справки.

Ответ 9

Я знаю, что вопрос о GCC, но для людей, которые ищут, как это сделать в других и/или нескольких компиляторах...

TL; DR

Возможно, вы захотите взглянуть на Хедли, который является одним из общедоступных заголовков C/C++, который я написал и который делает для вас многое из этого. Я помещу краткий раздел о том, как использовать Хедли для всего этого, в конце этого поста.

Отключение предупреждения

#pragma warning (disable: …) имеет эквиваленты в большинстве компиляторов:

  • MSVC: #pragma warning(disable:4996)
  • GCC: #pragma GCC diagnostic ignored "-W…" где многоточие является названием предупреждения; например, #pragma GCC diagnostic ignored "-Wdeprecated-declarations.
  • clang: #pragma clang diagnostic ignored "-W…". Синтаксис в основном такой же, как в GCC, и многие имена предупреждений совпадают (хотя многие не совпадают).
  • Компилятор Intel C: используйте синтаксис MSVC, но имейте в виду, что номера предупреждений совершенно разные. Пример: #pragma warning(disable:1478 1786).
  • diag_suppress: diag_suppress прагма diag_suppress: #pragma diag_suppress 1215,1444
  • TI: есть прагма diag_suppress с тем же синтаксисом (но с разными номерами предупреждений!), pragma diag_suppress 1291,1718 PGI: pragma diag_suppress 1291,1718
  • Oracle Developer Studio (suncc): есть прагма error_messages. Досадно, что предупреждения для компиляторов C и C++ различны. Оба из них отключают в основном одни и те же предупреждения:
    • C: #pragma error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)
    • C++: #pragma error_messages(off,symdeprecated,symdeprecated2)
  • IAR: также использует diag_suppress как PGI и TI, но синтаксис другой. Некоторые номера предупреждений одинаковы, но другие разошлись: #pragma diag_suppress=Pe1444,Pe1215
  • Pelles C: аналогично MSVC, хотя опять-таки цифры разные #pragma warn(disable:2241)

Для большинства компиляторов часто хорошей идеей является проверка версии компилятора, прежде чем пытаться отключить ее, в противном случае вы просто получите другое предупреждение. Например, в GCC 7 добавлена поддержка -Wimplicit-fallthrough предупреждения -Wimplicit-fallthrough, поэтому, если вы заботитесь о GCC до 7, вы должны сделать что-то вроде

#if defined(__GNUC__) && (__GNUC__ >= 7)
#  pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
#endif

Для clang и компиляторов, основанных на clang, таких как более новые версии XL C/C++ и armclang, вы можете проверить, знает ли компилятор о конкретном предупреждении, используя __has_warning().

#if __has_warning("-Wimplicit-fallthrough")
#  pragma clang diagnostic ignored "-Wimplicit-fallthrough"
#endif

Конечно, вы также должны проверить, существует ли __has_warning():

#if defined(__has_warning)
#  if __has_warning("-Wimplicit-fallthrough")
#    pragma clang diagnostic ignored "-Wimplicit-fallthrough"
#  endif
#endif

Вы можете испытать желание сделать что-то вроде

#if !defined(__has_warning)
#  define __has_warning(warning)
#endif

Таким образом, вы можете использовать __has_warning немного легче. Clang даже предлагает нечто подобное для __has_builtin() в их руководстве. Не делай этого. Другой код может проверить наличие __has_warning и вернуться к проверке версий компилятора, если он не существует, и если вы определите __has_warning вы нарушите их код. Правильный способ сделать это - создать макрос в вашем пространстве имен. Например:

#if defined(__has_warning)
#  define MY_HAS_WARNING(warning) __has_warning(warning)
#else
#  define MY_HAS_WARNING(warning) (0)
#endif

Тогда вы можете делать такие вещи, как

#if MY_HAS_WARNING(warning)
#  pragma clang diagnostic ignored "-Wimplicit-fallthrough"
#elif defined(__GNUC__) && (__GNUC__ >= 7)
#  pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
#endif

Нажатие и сование

Многие компиляторы также поддерживают способ вставлять предупреждения в стек. Например, это отключит предупреждение в GCC для одной строки кода, а затем вернет его в предыдущее состояние:

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated"
call_deprecated_function();
#pragma GCC diagnostic pop

Конечно, между компиляторами нет большого согласия по поводу синтаксиса:

  • GCC 4. 6+: #pragma GCC diagnostic push/#pragma GCC diagnostic pop
  • clang: #pragma clang diagnostic push/#pragma diagnostic pop
  • Intel 13+ (и, возможно, ранее): #pragma warning(push)/#pragma warning(pop)
  • MSVC 15+ (VS 9.0/2008): #pragma warning(push)/#pragma warning(pop)
  • ARM 5. 6+: #pragma push/#pragma pop
  • TI 8. 1+: #pragma diag_push/#pragma diag_pop
  • Pelles C 2. 90+ (и, возможно, ранее): #pragma warning(push) прагме #pragma warning(push)/#pragma warning(pop)

Если память служит, для некоторых очень старых версий GCC (таких как 3.x, IIRC) прагмы push/pop должны быть вне функции.

Сокрытие кровавых деталей

Для большинства компиляторов можно скрыть логику за макросами, используя _Pragma, которая была представлена в C99. Даже в не-C99 режиме большинство компиляторов поддерживают _Pragma; большое исключение - MSVC, у которого есть собственное __pragma слово __pragma с другим синтаксисом. Стандартная _Pragma принимает строку, версия Microsoft не:

#if defined(_MSC_VER)
#  define PRAGMA_FOO __pragma(foo)
#else
#  define PRAGMA_FOO _Pragma("foo")
#endif
PRAGMA_FOO

Примерно эквивалентно, после предварительной обработки,

#pragma foo

Это позволяет нам создавать макросы, чтобы мы могли писать код

MY_DIAGNOSTIC_PUSH
MY_DIAGNOSTIC_DISABLE_DEPRECATED
call_deprecated_function();
MY_DIAGNOSTIC_POP

И спрячьте все уродливые проверки версий в определениях макросов.

Простой способ: Хедли

Теперь, когда вы понимаете механику того, как делать подобные вещи, сохраняя при этом чистый код, вы понимаете, что делает один из моих проектов, Хедли. Вместо того, чтобы копаться в тоннах документации и/или устанавливать столько версий компиляторов, сколько вы можете протестировать, вы можете просто включить Hedley (это один общедоступный заголовок C/C++) и покончить с этим. Например:

#include "hedley.h"

HEDLEY_DIAGNOSTIC_PUSH
HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
call_deprecated();
HEDLEY_DIAGNOSTIC_POP

Отключит предупреждение о вызове устаревшей функции в GCC, clang, ICC, PGI, MSVC, TI, IAR, ODS, Pelles и, возможно, других (возможно, я не буду обновлять этот ответ, когда обновляю Хедли). И на компиляторах, которые, как известно, не работают, макросы будут предварительно обработаны, и ваш код продолжит работать с любым компилятором. Конечно, HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED - не единственное предупреждение, о котором знает Хедли, и не отключение предупреждений, которые может сделать Хедли, но, надеюсь, вы поняли идею.