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?
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?
Odpowiedzi:
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 */
push
i dwa pop
s - może być inny push
na początku brakuje?
Aby skompresować wszystko, jest to przykład tymczasowego wyłączenia ostrzeżenia:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-result"
write(foo, bar, baz);
#pragma GCC diagnostic pop
Więcej informacji można znaleźć w dokumentacji GCC na temat pragmatyki diagnostycznej .
gcc-4.9
po prostu całkowicie ignoruje tę linię.
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.c
kodu ź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ż argc
nie jest używany, a ustawienia są hardcore ( -W -Wall -pedantic -Werror
).
Istnieje 5 rzeczy, które możesz zrobić:
__attribute__
_Pragma
#pragma
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ż argc
jest on zbędny z !*argv
( NULL
po ostatnim elemencie).
__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 armcc
również) i nie będzie zrozumiały dla wielu innych kompilatorów. Wstaw __attribute__((unused))
makro, jeśli chcesz przenosić kod.
_Pragma
operator_Pragma
moż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ą _Pragma
operatora jest to, że można go umieścić w makrach, co nie jest możliwe w przypadku #pragma
dyrektywy.
Wada: to prawie taktyczny nuke, ponieważ działa w oparciu o linię zamiast w oparciu o deklarację.
_Pragma
Operatora 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 .
Możemy dodać następujący wiersz do, Makefile
aby 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.
improving the source
dział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.
gcc
jak również clang
.
#define UNUSED(x) ((void)x)
używane do wyciszania ostrzeżeń. Myślę, że to było w ReactOS?
_Pragma("GCC diagnostic pop") \
tak powinno być _Pragma("GCC diagnostic pop")
.
#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.
#pragma GCC diagnostic ignored "-Wformat"
Zamień „-Wformat” na nazwę flagi ostrzegawczej.
AFAIK nie ma możliwości użycia semantyki push / pop dla tej opcji.
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
Wiem, że pytanie dotyczy GCC, ale dla osób szukających tego, jak to zrobić w innych i / lub wielu kompilatorach…
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.
#pragma warning (disable: …)
ma odpowiedniki w większości kompilatorów:
#pragma warning(disable:4996)
#pragma GCC diagnostic ignored "-W…"
gdzie elipsa jest nazwą ostrzeżenia; np , #pragma GCC diagnostic ignored "-Wdeprecated-declarations
.#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).#pragma warning(disable:1478 1786)
.diag_suppress
pragma:#pragma diag_suppress 1215,1444
diag_suppress
pragma o tej samej składni (ale różnych liczbach ostrzegawczych!) Jak PGI:pragma diag_suppress 1291,1718
error_messages
pragma. Irytujące ostrzeżenia są różne dla kompilatorów C i C ++. Oba wyłączają w zasadzie te same ostrzeżenia:
#pragma error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)
#pragma error_messages(off,symdeprecated,symdeprecated2)
diag_suppress
takich 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
#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-fallthrough
ostrzeż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_warning
nieco łatwiej. Clang sugeruje nawet coś podobnego dla __has_builtin()
makra w swoim podręczniku. Nie rób tego . Inny kod może __has_warning
sprawdzać 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
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:
#pragma GCC diagnostic push
/#pragma GCC diagnostic pop
#pragma clang diagnostic push
/#pragma diagnostic pop
#pragma warning(push)
/#pragma warning(pop)
#pragma warning(push)
/#pragma warning(pop)
#pragma push
/#pragma pop
#pragma diag_push
/#pragma diag_pop
#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ą.
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 __pragma
słowo kluczowe o innej składni. Standard _Pragma
przyjmuje 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.
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_DEPRECATED
nie 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ł.
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.
if ((p=malloc(cnt)) != NULL) ...
że to właśnie robi kompilator za kulisami.
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.