Як відключити попередження GCC для кількох рядків коду


220

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


1
можливий дублікат вимкнення конкретних попереджень у gcc - На жаль, саме це питання є дурпом (але не закритим). Це просто трапляється той, який з’явився в розділі "Пов'язані". У будь-якому випадку, про це вже кілька разів запитували і відповіли.
Тайлер Макенрі

1
@paxdiablo: Я надаю зворотній бік. Я підняв рівень попередження дуже високо, і хочу розрізати попередження по черзі, що я перевірив, що це нормально.
Метт Столяр

4
@Tyler McHenry: Якщо ви перевірили більш ретельно, ви можете зауважити, що пов'язане питання містить рішення на один файл, саме те, про яке я згадував у своєму власному запитанні, як незадовільний (я навіть вкрав посилання).
Метт Столяр

6
@paxdiablo, компілятори надають помилкові позитиви, іноді ви хочете компілювати з -Werror, але не мають цих помилкових позитивів блокувати збірку. тому відключення конкретних випадків і коментування чому - в деяких випадках має сенс. Існують і інші випадки, коли це може бути зручно - як автоматичний генеруючий код, який створює нешкідливі попередження, які не так просто входити та змінювати (оскільки код генерується), хоча в такому випадку відключення файлу швидше буде рішення.
ideaman42

Відповіді:


221

Здається, це можна зробити . Я не можу визначити версію 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 */

14
один pushі два popс - може бути інший pushна початку відсутній?
прірва.7

37
"#pragma GCC діагностичний поштовх #pragma Діагностичний поп GCC викликає, щоб GCC запам'ятав стан діагностики кожного натискання і відновив цю точку на кожному попсі. Якщо поп не має відповідного натискання, параметри командного рядка відновлюються. " - з посібника GCC: gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html
bobpaul

11
Для довідки, gcc версія 4.4.3 підтримує помилку / попередження / ігнорується, але не push / pop
frankster

12
Перша версія GCC, яка мала діагностичний push / pop, - GCC 4.6.4 . Я визначив це, переглянувши розділ Diagnostic-Pragmas.html # Diagnostic-Pragmas для кожної версії GCC у документації GCC
bitek

5
Прикро, що це не працює на практиці. У деяких випадках він створює більше попереджень. А може, правильніше, це не працює на практиці для GCC 4.7 - 5.1. Дивіться, наприклад, GCC не шанує "прагматичну діагностику GCC", щоб замовчувати попередження .
jww

108

Щоб викреслити все, це приклад тимчасово відключення попередження:

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

Ви можете перевірити документацію GCC щодо діагностичних праг для отримання більш детальної інформації.


2
Має працювати, але мій gcc-4.9просто ігнорує цю лінію повністю.
Олексій Петренко

31

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

Даунсайд: Це майже тактична ядерна сила, оскільки вона працює лінійно, а не декларацією.

Зауважте, що подібний синтаксис існує в кланге .

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

Ми можемо додати наступний рядок Makefileдо придушення попередження спеціально для ставок:

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

.PHONY: all
all: puts

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

Напевно, цього не хочеться у вашому конкретному випадку, але це може допомогти іншим читачам, які потрапляють у подібні ситуації.


2
re: improving the sourceтакож буде працювати над зміною декларації main на int main(int, const char* argv[]) { ... }, не даючи аргументу імені, ви скажете компілятору, що він буде невикористаний.
Джессі Чизгольм

1
@JesseChisholm опускання імені параметра при визначенні функції неможливо. Див 6.9.1 Функціональні definintions ІСО / IEC9899, § 5 «Якщо описувач містить список типів параметрів, декларація кожного параметра повинна включати в себе ідентифікатор [...]» І правильно , так що код буде відкинутий gcc, а також clang.
Крістіан Худжер

1
Інша закономірність - це просто зробити команду змінної для анулювання. Насправді я бачив у проекті такий макрос: #define UNUSED(x) ((void)x)використовується для замовчування попереджень. Я думаю, це було в ReactOS?
Пол

1
Я не думаю, що після цього вам потрібен зворотний нахил, ні? я _Pragma("GCC diagnostic pop") \ просто повинен бути, _Pragma("GCC diagnostic pop")я думаю.
Габріель Степлес

1
@GabrielStaples Це правильно, дякую, що помітили, я оновив відповідь.
Крістіан Худжер

20
#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 він працює, для деяких - ні.


3
Ви справжній MVP
zeboidlund

19
#pragma GCC diagnostic ignored "-Wformat"

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

AFAIK для цього параметра немає можливості використовувати push / pop семантику.


4
Прикро, що це не працює на практиці. У деяких випадках він створює більше попереджень. А може, правильніше, це не працює на практиці для GCC 4.7 - 5.1. Дивіться, наприклад, GCC не шанує "прагматичну діагностику GCC", щоб замовчувати попередження .
jww

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

2
Чи не слід цим краще займатися в системних каталогах gcc ?
Червоний XIII

@RedXIII - так, це варіант, якщо ви можете скласти список таких каталогів і вказати в командному рядку gcc. Однак багато разів компілятор запускається глибоко в конвеєр, або ви не дуже контролюєте, як хтось інший повинен складати ваш код. У цих випадках вище, мабуть, краще рішення.
Shital Shah

5

Я знаю, що питання стосується 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.
  • брязкіт: #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
  • Гранули 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трохи легше. Кланг навіть пропонує щось подібне для __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
  • кланг: #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). І на компіляторах, які, як відомо, не працюють, макроси будуть попередньо оброблені ні до чого, тому ваш код продовжить працювати з будь-яким компілятором. Звичайно, HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATEDце не єдине попередження, про яке знає Хедлі, і не відключення попереджень, про які може зробити Хедлі, але, сподіваємось, ви зрозумієте цю ідею.


3

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


2
Можливо, так. Моя мета - не доводити будь-якої загальної справи, а спостереження щодо того, якою є філософія gcc щодо попередження попередження.
R .. GitHub ЗАСТАНОВИТИ ДІЯ

компілятор поводиться по-різному з попередженнями з доданими дужками?!?! ?? !!!! ОЦЕ ТАК! Це несподівано.
Jason S

1
@JasonS пароні не змінюють попередження Wrt про поведінку компілятора, те, що він робить, - це змінити семантику висловлювання. Додаткові парени змушують компілятор закінчувати завдання і зберігає його остаточне значення як вираз, який не заслуговує на попередження. Якщо ви хочете зрозуміти, ви можете сказати if ((p=malloc(cnt)) != NULL) ..., що саме так робить компілятор поза кадром.
Джессі Чісгольм

@JesseChisholm: Я не думаю, що ваше пояснення є точним.
R .. GitHub СТОП ДОПОМОГАТИ

3

Для тих, хто знайшов цю сторінку, яка шукає спосіб зробити це в 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 для довідок.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.