Jak wyłączyć ostrzeżenia GCC dla kilku linii kodu


220

W Visual C ++ można używać #pragma warning (disable: ...). Odkryłem również, że w GCC można przesłonić flagi kompilatora plików . Jak mogę to zrobić dla „następnej linii” lub z semantyką push / pop wokół obszarów kodu za pomocą GCC?


1
możliwy duplikat wyłączenia określonych ostrzeżeń w gcc - Ups, właściwie to pytanie jest duplikatem (ale nie zamknięte). Tak się składa, że ​​pojawił się pod „Powiązane”. Tak czy inaczej, zostało to zadane kilkakrotnie na SO.
Tyler McHenry

1
@paxdiablo: Skończyłem odwrotnie. Podniosłem poziom ostrzegawczy bardzo wysoko i chcę wyciskać ostrzeżenia linia po linii, które potwierdziłem, że są w porządku.
Matt Joiner

4
@Tyler McHenry: Jeśli sprawdziłeś dokładniej, możesz zauważyć, że połączone pytanie zawiera rozwiązanie dla poszczególnych plików, dokładnie takie, o którym wspomniałem w swoim własnym pytaniu jako niezadowalające (nawet skradłem link).
Matt Joiner

6
@paxdiablo, kompilatory dają fałszywe alarmy, czasem chcesz skompilować z -Werror, ale nie chcesz, aby te fałszywe alarmy blokowały kompilację. więc wyłączenie szczególnych przypadków i komentowanie, dlaczego - w niektórych przypadkach ma sens. Są też inne przypadki, w których może to być przydatne - na przykład automatyczne generowanie kodu, który generuje nieszkodliwe ostrzeżenia, które nie są tak łatwe do wejścia i zmiany (ponieważ kod jest generowany), chociaż w takim przypadku bardziej prawdopodobne jest wyłączenie jednego pliku rozwiązanie.
ideasman42,

Odpowiedzi:


221

Wygląda na to, że można to zrobić . Nie jestem w stanie określić wersji GCC, która została dodana, ale było to przed czerwcem 2010 roku.

Oto przykład:

#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
jeden pushi dwa pops - może być inny pushna początku brakuje?
abyss.7,

37
"#pragma push diagnostyczny GCC #pragma pop diagnostyczny GCC Powoduje, że GCC zapamiętuje stan diagnostyki z każdego push i przywraca do tego punktu przy każdym pop. Jeśli pop nie ma pasującego pushu, opcje wiersza poleceń są przywracane. „ - z podręcznika GCC: gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html
bobpaul

11
Dla porównania, gcc w wersji 4.4.3 obsługuje błędy / ostrzeżenia / ignorowane, ale nie push / pop
frankster

12
Pierwszą wersją GCC z diagnostycznym push / pop jest GCC 4.6.4 . Ustaliłem to, przeglądając sekcję Diagnostic-Pragmas.html # Diagnostic-Pragmas dla każdej wersji GCC w dokumentacji GCC
bitek

5
Szkoda, że ​​to nie działa w praktyce. W niektórych przypadkach generuje więcej ostrzeżeń. A może, bardziej poprawnie, nie działa w praktyce dla GCC 4.7 do 5.1. Zobacz na przykład GCC nie honoruje „pragmatycznej diagnostyki GCC” w celu wyciszenia ostrzeżeń .
jww


31

TL; DR : Jeśli to działa, unikaj lub używaj takich specyfikatorów __attribute__, inaczej _Pragma.

To jest krótka wersja mojego artykułu na blogu Tłumienie ostrzeżeń w GCC i Clang .

Rozważ następujące Makefile

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

.PHONY: all
all: puts

do budowania następującego puts.ckodu źródłowego

#include <stdio.h>

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

Nie będzie się kompilował, ponieważ argcnie jest używany, a ustawienia są hardcore ( -W -Wall -pedantic -Werror).

Istnieje 5 rzeczy, które możesz zrobić:

  • Popraw kod źródłowy, jeśli to możliwe
  • Użyj specyfikatora deklaracji, takiego jak __attribute__
  • Posługiwać się _Pragma
  • Posługiwać się #pragma
  • Użyj opcji wiersza polecenia.

Ulepszanie źródła

Pierwszą próbą powinno być sprawdzenie, czy można poprawić kod źródłowy, aby pozbyć się ostrzeżenia. W tym przypadku nie chcemy zmieniać algorytmu tylko z tego powodu, ponieważ argcjest on zbędny z !*argv( NULLpo ostatnim elemencie).

Korzystanie ze specyfikatora deklaracji, np __attribute__

#include <stdio.h>

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

Jeśli masz szczęście, standard określa specyfikację twojej sytuacji, np _Noreturn.

__attribute__jest zastrzeżonym rozszerzeniem GCC (obsługiwanym przez Clanga i niektóre inne kompilatory, jak armccrównież) i nie będzie zrozumiały dla wielu innych kompilatorów. Wstaw __attribute__((unused))makro, jeśli chcesz przenosić kod.

_Pragma operator

_Pragmamoże być stosowany jako alternatywa dla #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")

Główną zaletą _Pragmaoperatora jest to, że można go umieścić w makrach, co nie jest możliwe w przypadku #pragmadyrektywy.

Wada: to prawie taktyczny nuke, ponieważ działa w oparciu o linię zamiast w oparciu o deklarację.

_PragmaOperatora wprowadzono C99.

#pragma dyrektywa.

Możemy zmienić kod źródłowy, aby ukryć ostrzeżenie dla regionu kodu, zwykle całej funkcji:

#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

Wada: to prawie taktyczny nuke, ponieważ działa w oparciu o linię zamiast w oparciu o deklarację.

Zauważ, że podobna składnia występuje w clang .

Pomijanie ostrzeżenia w wierszu poleceń dla pojedynczego pliku

Możemy dodać następujący wiersz do, Makefileaby pominąć ostrzeżenie specjalnie dla putów:

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

.PHONY: all
all: puts

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

Prawdopodobnie nie jest to pożądane w konkretnym przypadku, ale może pomóc innym czytającym, którzy znajdują się w podobnych sytuacjach.


2
re: improving the sourcedziałałoby również zmienić deklarację main na int main(int, const char* argv[]) { ... }nie nadając argumentowi nazwy, informujesz kompilator, że będzie nieużywany.
Jesse Chisholm,

1
@JesseChisholm pominięcie nazwy parametru w definicji funkcji nie jest możliwe. Zobacz 6.9.1 definintions funkcją ISO / IEC9899, §5 „Jeśli declarator zawiera listę typ parametru, deklaracja każdego parametru powinna zawierać identyfikator [...]”, a właściwie tak kod zostanie odrzucony przez gccjak również clang.
Christian Hujer

1
Innym wzorem jest po prostu rzutowanie zmiennej w celu unieważnienia. W rzeczywistości widziałem w projekcie następujące makro: #define UNUSED(x) ((void)x)używane do wyciszania ostrzeżeń. Myślę, że to było w ReactOS?
Paul Stelian,

1
Nie sądzę, żebyś potrzebował potem odwrotnego ukośnika, nie? _Pragma("GCC diagnostic pop") \ tak powinno być _Pragma("GCC diagnostic pop").
Gabriel Staples

1
@GabrielStaples Zgadza się, dziękuję za uwagę, zaktualizowałem odpowiedź.
Christian Hujer

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

To powinno załatwić sprawę dla gcc, clang i msvc

Można wywołać np .:

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

patrz https://gcc.gnu.org/onlinedocs/cpp/Pragmas.html , http://clang.llvm.org/docs/UsersManual.html#controlling-diagnostics-via-pragmas i https://msdn.microsoft .pl / de-DE / library / d9x1s805.aspx aby uzyskać więcej informacji

Potrzebujesz co najmniej wersji 4.02, aby korzystać z tego rodzaju pragmów dla gcc, nie jesteś pewien msvc i brzękaj o wersjach.

Wygląda na to, że obsługa push pop dla gcc jest trochę zepsuta. Jeśli ponownie włączysz ostrzeżenie, nadal otrzymujesz ostrzeżenie dla bloku, który był w bloku DISABLE_WARNING / ENABLE_WARNING. W niektórych wersjach gcc działa, w niektórych nie.


3
You da real MVP
zeboidlund


6

Miałem ten sam problem z bibliotekami zewnętrznymi, takimi jak nagłówki ROS. Lubię używać następujących opcji w pliku CMakeLists.txt do ściślejszej kompilacji:

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

Powoduje to jednak wszelkiego rodzaju błędy pedantyczne również w bibliotekach zewnętrznych. Rozwiązaniem jest wyłączenie wszystkich ostrzeżeń pedantycznych przed dołączeniem bibliotek zewnętrznych i ponownym włączeniem w następujący sposób:

//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
Czy nie powinno to być lepiej obsługiwane przez katalogi systemowe gcc ?
Czerwony XIII,

@ RedXIII - tak, jest to opcja, jeśli możesz zrobić listę takich katalogów i podać w wierszu poleceń gcc. Jednak wiele razy kompilator jest wywoływany głęboko w potoku lub nie masz dużej kontroli nad tym, jak ktoś inny powinien skompilować twój kod. W tych przypadkach powyższe jest prawdopodobnie lepszym rozwiązaniem.
Shital Shah

5

Wiem, że pytanie dotyczy GCC, ale dla osób szukających tego, jak to zrobić w innych i / lub wielu kompilatorach…

TL; DR

Możesz rzucić okiem na Hedley , który jest napisanym przeze mnie publicznym nagłówkiem C / C ++, który robi dużo dla ciebie z tych rzeczy. Na końcu tego postu zamieszczę krótką sekcję o tym, jak używać Hedley do tego wszystkiego.

Wyłączam ostrzeżenie

#pragma warning (disable: …) ma odpowiedniki w większości kompilatorów:

  • MSVC: #pragma warning(disable:4996)
  • GCC: #pragma GCC diagnostic ignored "-W…"gdzie elipsa jest nazwą ostrzeżenia; np , #pragma GCC diagnostic ignored "-Wdeprecated-declarations.
  • szczęk: #pragma clang diagnostic ignored "-W…" . Składnia jest w zasadzie taka sama jak w GCC, a wiele nazw ostrzeżeń jest takich samych (choć wiele nie jest).
  • Kompilator Intel C: Użyj składni MSVC, ale pamiętaj, że liczby ostrzegawcze są zupełnie inne. Przykład:#pragma warning(disable:1478 1786) .
  • ChOG: Istnieje diag_suppress pragma:#pragma diag_suppress 1215,1444
  • TI: Istnieje diag_suppress pragma o tej samej składni (ale różnych liczbach ostrzegawczych!) Jak PGI:pragma diag_suppress 1291,1718
  • Oracle Developer Studio (suncc): istnieje error_messagespragma. Irytujące ostrzeżenia są różne dla kompilatorów C i C ++. Oba wyłączają w zasadzie te same ostrzeżenia:
    • DO: #pragma error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)
    • C ++: #pragma error_messages(off,symdeprecated,symdeprecated2)
  • IAR: używa również diag_suppresstakich jak PGI i TI, ale składnia jest inna. Niektóre numery ostrzegawcze są takie same, ale ja inne się rozeszły:#pragma diag_suppress=Pe1444,Pe1215
  • Pelles C: podobny do MSVC, choć znowu liczby są różne #pragma warn(disable:2241)

W przypadku większości kompilatorów często dobrym pomysłem jest sprawdzenie wersji kompilatora przed próbą jej wyłączenia, w przeciwnym razie pojawi się kolejne ostrzeżenie. Na przykład GCC 7 dodał obsługę -Wimplicit-fallthroughostrzeżenia, więc jeśli zależy ci na GCC przed 7, powinieneś zrobić coś takiego

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

W przypadku clang i kompilatorów opartych na clang, takich jak nowsze wersje XL C / C ++ i armclang, możesz sprawdzić, czy kompilator wie o danym ostrzeżeniu za pomocą __has_warning()makra.

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

Oczywiście musisz również sprawdzić, czy __has_warning()makro istnieje:

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

Możesz mieć ochotę zrobić coś takiego

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

Możesz więc użyć __has_warningnieco łatwiej. Clang sugeruje nawet coś podobnego dla __has_builtin()makra w swoim podręczniku. Nie rób tego . Inny kod może __has_warningsprawdzać wersje kompilatora i polegać na nim, jeśli nie istnieje, a jeśli go zdefiniujesz __has_warning, złamiesz jego kod. Właściwym sposobem na to jest utworzenie makra w przestrzeni nazw. Na przykład:

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

Następnie możesz robić takie rzeczy jak

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

Pchanie i strzelanie

Wiele kompilatorów obsługuje również sposób wypychania i wyrzucania ostrzeżeń na stos. Na przykład spowoduje to wyłączenie ostrzeżenia w GCC dla jednego wiersza kodu, a następnie przywrócenie go do poprzedniego stanu:

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

Oczywiście nie ma dużej zgody między kompilatorami na temat składni:

  • GCC 4.6+: #pragma GCC diagnostic push/#pragma GCC diagnostic pop
  • clang: #pragma clang diagnostic push/#pragma diagnostic pop
  • Intel 13+ (i prawdopodobnie wcześniej): #pragma warning(push)/#pragma warning(pop)
  • MSVC 15+ (VS 9.0 / 2008): #pragma warning(push)/#pragma warning(pop)
  • RAMIĘ 5.6+: #pragma push/#pragma pop
  • TI 8.1+: #pragma diag_push/#pragma diag_pop
  • Pelles C 2.90+ (i prawdopodobnie wcześniej): #pragma warning(push)/#pragma warning(pop)

Jeśli pamięć służy, w niektórych bardzo starych wersjach GCC (takich jak 3.x, IIRC) pragma push / pop musiała znajdować się poza funkcją.

Ukrywanie krwawych szczegółów

W przypadku większości kompilatorów możliwe jest ukrycie logiki za pomocą makr _Pragma, która została wprowadzona w C99. Nawet w trybie innym niż C99 większość kompilatorów obsługuje _Pragma; dużym wyjątkiem jest MSVC, który ma własne __pragmasłowo kluczowe o innej składni. Standard _Pragmaprzyjmuje ciąg, wersja Microsoft nie:

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

Jest mniej więcej równoważny, po uprzednim przetworzeniu, z

#pragma foo

To pozwala nam tworzyć makra, dzięki czemu możemy pisać jak kod

MY_DIAGNOSTIC_PUSH
MY_DIAGNOSTIC_DISABLE_DEPRECATED
call_deprecated_function();
MY_DIAGNOSTIC_POP

I ukryj wszystkie brzydkie kontrole wersji w definicjach makr.

Prosty sposób: Hedley

Teraz, gdy rozumiesz mechanikę robienia takich rzeczy przenośnie, utrzymując kod w czystości, rozumiesz, co robi jeden z moich projektów, Hedley . Zamiast przeglądać mnóstwo dokumentacji i / lub instalować tyle wersji kompilatorów, ile można testować, wystarczy dołączyć Hedley (jest to pojedynczy nagłówek C / C ++ domeny publicznej) i gotowe. Na przykład:

#include "hedley.h"

HEDLEY_DIAGNOSTIC_PUSH
HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
call_deprecated();
HEDLEY_DIAGNOSTIC_POP

Wyłączy ostrzeżenie o wywołaniu przestarzałej funkcji w GCC, clang, ICC, PGI, MSVC, TI, IAR, ODS, Pelles i ewentualnie innych (prawdopodobnie nie będę zawracał sobie głowy aktualizowaniem tej odpowiedzi podczas aktualizacji Hedley). A na kompilatorach, o których nie wiadomo, że działają, makra zostaną wstępnie przetworzone do niczego, więc kod będzie kontynuował pracę z dowolnym kompilatorem. Oczywiście HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATEDnie jest to jedyne ostrzeżenie, o którym wie Hedley, ani też nie wyłącza ostrzeżeń, które może zrobić tylko Hedley, ale mam nadzieję, że wpadłeś na ten pomysł.


3

Zamiast wyciszać ostrzeżenia, styl gcc zwykle polega na użyciu standardowych konstrukcji C lub __attribute__rozszerzenia, aby poinformować kompilator o swoich zamiarach. Na przykład ostrzeżenie o przypisaniu zastosowanym jako warunek jest tłumione poprzez umieszczenie przypisania w nawiasach, tzn. if ((p=malloc(cnt)))Zamiast if (p=malloc(cnt)). Ostrzeżenia o nieużywanych argumentach funkcji mogą być tłumione przez jakieś dziwne __attribute__, których nigdy nie pamiętam, lub przez samodzielne przypisanie itp. Ale ogólnie wolę po prostu globalnie wyłączyć dowolną opcję ostrzegania, która generuje ostrzeżenia o rzeczach, które wystąpią we właściwym kodzie.


2
Może tak. Moim zamiarem nie jest udowodnienie żadnego ogólnego wzorca przypadków, a raczej spostrzeżenie na temat filozofii gcc dotyczącej tłumienia ostrzeżeń.
R .. GitHub ZATRZYMAJ POMÓC LODO

kompilator zachowuje się inaczej z ostrzeżeniami w / r / t z dodanymi nawiasami?!?! ?? !!!! ŁAŁ! To jest nieoczekiwane.
Jason S

1
@JasonS parens nie zmienia zachowania kompilatora, nie ostrzega, zmienia semantykę instrukcji. Dodatkowe pareny powodują, że kompilator kończy zadanie i zachowuje swoją ostateczną wartość jako wyrażenie, które nie zasługuje na żadne ostrzeżenie. Jeśli chcesz przejrzystości, możesz powiedzieć, if ((p=malloc(cnt)) != NULL) ...że to właśnie robi kompilator za kulisami.
Jesse Chisholm,

@JesseChisholm: Nie sądzę, żeby twoje wyjaśnienie było dokładne.
R .. GitHub ZATRZYMAJ POMOC ICE

3

Dla tych, którzy znaleźli tę stronę i szukają sposobu na zrobienie tego w IAR, spróbuj tego:

#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

Zobacz http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0472m/chr1359124244797.html w celach informacyjnych.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.