Вопрос:
В Visual C++ можно использовать #pragma warning (disable:…). Также я обнаружил, что в GCC вы можете переопределить флаги компилятора файлов. Как я могу сделать это для “следующей строки”, или с семантикой push/pop вокруг областей кода, используя GCC?
Лучший ответ:
Похоже, что это можно сделать. Я не могу определить версию 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 */ Ответ №1
Чтобы отключить все, это пример временно отключения предупреждения:
#pragma GCC diagnostic push #pragma GCC diagnostic ignored «-Wunused-result» write(foo, bar, baz); #pragma GCC diagnostic pop
Более подробную информацию можно найти в документации GCC по диагностическим прагмам.
Ответ №2
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
- Используйте параметр командной строки.
Содержание
- Улучшение источника
- Использование спецификатора объявления, например __attribute__
- _Pragma оператор
- директива #pragma.
- Подавление предупреждения в командной строке для одного файла
- TL; DR
- Отключение предупреждения
- Нажатие и сование
- Сокрытие кровавых деталей
- Простой способ: Хедли
Улучшение источника
Первая попытка должна проверять, можно ли улучшить исходный код, чтобы избавиться от предупреждения. В этом случае мы не хотим менять алгоритм только из-за этого, так как 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
Это, вероятно, не хочет, чтобы вы хотели в вашем конкретном случае, но это может помочь другим чтения, которые находятся в подобных ситуациях.
Ответ №3#pragma GCC diagnostic ignored «-Wformat»
Замените “-Wformat” на имя вашего предупреждающего флага.
AFAIK не существует возможности использовать семантику push/pop для этой опции.
Ответ №4#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 он работает, для некоторых это не так.
Ответ №5
У меня была такая же проблема с внешними библиотеками, как заголовки 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 Ответ №6
Вместо того, чтобы замалчивать предупреждения, стиль gcc обычно использует либо стандартные конструкторы C, либо расширение __attribute__, чтобы больше рассказать компилятору о ваших намерениях. Например, предупреждение о присваивании, которое используется как условие, подавляется путем помещения задания в круглые скобки, то есть if ((p=malloc(cnt))) вместо if (p=malloc(cnt)). Предупреждения о неиспользуемых аргументах функции могут быть подавлены с помощью некоторого нечетного __attribute__, который я никогда не запомню, или путем самоопределения и т.д. Но обычно я предпочитаю просто глобально отключать любую опцию предупреждения, которая генерирует предупреждения для вещей, которые будут возникать в правильном коде.
Ответ №7
Для тех, кто нашел эту страницу в поиске способа сделать это в 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 для справки.
Ответ №8
Я знаю, что вопрос о 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 – не единственное предупреждение, о котором знает Хедли, и не отключение предупреждений, которые может сделать Хедли, но, надеюсь, вы поняли идею.