Как отключить предупреждения GCC для нескольких строк кода - PullRequest
188 голосов
/ 31 июля 2010

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

Ответы [ 9 ]

196 голосов
/ 03 августа 2010

Похоже, это можно сделать . Я не могу определить версию 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 */
92 голосов
/ 24 сентября 2014

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

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

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

21 голосов
/ 27 ноября 2017

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;
}

Itне будет компилироваться, потому что 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

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

17 голосов
/ 23 марта 2016
#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 и clang относительно версий.

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

16 голосов
/ 31 июля 2010
#pragma GCC diagnostic ignored "-Wformat"

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

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

5 голосов
/ 26 апреля 2016

У меня была такая же проблема с внешними библиотеками, такими как заголовки 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
3 голосов
/ 20 сентября 2016

Для тех, кто нашел эту страницу, ищет способ сделать это в 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 для справки.

3 голосов
/ 31 июля 2010

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

2 голосов
/ 27 апреля 2019

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

TL; DR

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

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

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

  • MSVC: #pragma warning(disable:4996)
  • GCC: #pragma GCC diagnostic ignored "-W…", где многоточие является названием предупреждения; например , #pragma GCC diagnostic ignored "-Wdeprecated-declarations.
  • лязг: #pragma clang diagnostic ignored "-W…".Синтаксис в основном такой же, как в GCC, и многие имена предупреждений совпадают (хотя многие не совпадают).
  • Компилятор Intel C: используйте синтаксис MSVC, но имейте в виду, что номера предупреждений полностьюразные.Пример: #pragma warning(disable:1478 1786).
  • PGI: существует diag_suppress прагма: #pragma diag_suppress 1215,1444
  • TI: существует прагма diag_suppress с тем же синтаксисом (но с разными номерами предупреждений!) как 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, поэтому, если вы заботитесь о 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(pop)

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

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

ДляВ большинстве компиляторов можно скрыть логику за макросами, используя _Pragma, который был представлен в C99.Даже в режиме без C99 большинство компиляторов поддерживают _Pragma;большое исключение - MSVC, у которого есть собственное ключевое слово __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 - не единственное предупреждение, о котором знает Хедли, и не отключение предупреждений, которые может сделать Хедли, но, надеюсь, вы поняли идею.

...