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