Flagi umożliwiające dokładne i szczegółowe ostrzeżenia g ++


122

Często w C poniżej gcc, zacznę od następującego zestawu flag ostrzegawczych (boleśnie zebranych z wielu źródeł):

-Wall -Wextra -Wformat-nonliteral -Wcast-align -Wpointer-arith -Wbad-function-cast \
-Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations -Winline -Wundef \
-Wnested-externs -Wcast-qual -Wshadow -Wwrite-strings -Wno-unused-parameter \
-Wfloat-equal -pedantic -ansi

Zbuduję (przynajmniej moje wersje do debugowania) z tym zestawem ostrzeżeń i naprawię wszystko, co tylko mogę (zwykle wszystko), a następnie usunę flagi tylko wtedy, gdy są nieistotne lub nie można ich naprawić (prawie nigdy nie jest). Czasami dodam również, -Werrorjeśli muszę odejść podczas kompilacji.

Po prostu uczę się C ++ (tak, jestem 15 lat spóźniony) i chciałbym zacząć od właściwej stopy.

Moje pytanie brzmi: czy ktoś ma wstępnie skompilowany podobny zestaw kompletnych flag ostrzegawczych dla C ++ poniżej g++? (Wiem, że wiele z nich będzie takich samych).


69
Jakie potrzeby gcc (ponieważ zdecydował rażąco leżą około -Wall) jest -Wbloody_everythingflaga :-)
paxdiablo

Możesz oznaczyć swoje pytanie jako fałszywe, ale możesz również podać ostatnią zmianę jako odpowiedź, ponieważ faktycznie odpowiedziałeś na swoje pytanie. I byłbym szczęśliwy, mogąc go wtedy
zagłosować

4
OP i @paxdiablo: GCC konsekwentnie odrzuca tego typu rzeczy, ale jest dostępne w Clang via -Weverything. Czytałem, że nawet programiści Clang ++ są trochę zaniepokojeni tym, że użytkownicy go włączają; najwyraźniej był przeznaczony tylko do wewnętrznego użytku deweloperskiego. Nie ma to jednak sensu, ponieważ włączenie -Weverythingjest prawdopodobnie najlepszym sposobem na odkrycie potencjalnie przydatnych ostrzeżeń, o których wcześniej nie wiedziałeś.
Kyle Strand

1
OP i @paxdiablo Jest teraz sposób na ustalenie pełnej listy ostrzeżeń dla danej wersji GCC: github.com/barro/compiler-warnings
Kyle Strand

Odpowiedzi:


138

Przejrzałem i znalazłem minimalny zestaw załączników, które powinny otrzymać maksymalny poziom ostrzeżenia. Następnie usunąłem z tej listy zestaw ostrzeżeń, które moim zdaniem w rzeczywistości nie wskazują, że dzieje się coś złego, lub mają zbyt wiele fałszywych alarmów, aby można je było wykorzystać w prawdziwej kompilacji. Skomentowałem, dlaczego każdy z wykluczonych przeze mnie został wykluczony. Oto mój ostatni zestaw sugerowanych ostrzeżeń:

-pedantic -Wall -Wextra -Wcast-align -Wcast-qual -Wctor-dtor-privacy -Wdisabled-optimization -Wformat=2 -Winit-self -Wlogical-op -Wmissing-declarations -Wmissing-include-dirs -Wnoexcept -Wold-style-cast -Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-conversion -Wsign-promo -Wstrict-null-sentinel -Wstrict-overflow=5 -Wswitch-default -Wundef -Werror -Wno-unused

Wątpliwe ostrzeżenia, które są obecne:

  • Uwzględniam, -Wno-unusedponieważ często mam zmienne, o których wiem, że będę używać później, ale nie mam jeszcze napisanych funkcji. Usunięcie ostrzeżeń o tym pozwala mi pisać w preferowanym przeze mnie stylu, polegającym na sporadycznym odraczaniu realizacji rzeczy. Warto od czasu do czasu to wyłączyć, aby mieć pewność, że nic nie prześlizgnie się przez szczeliny.

  • -Wdisabled-optimizationwydaje się być silnym ustawieniem preferencji użytkownika. Właśnie dodałem to do mojej kompilacji (tylko dla zoptymalizowanych kompilacji z oczywistych powodów) i nic nie wyszło, więc nie wydaje się być szczególnie rozmownym ostrzeżeniem, przynajmniej ze względu na sposób, w jaki koduję. Dołączam to (nawet jeśli kod, który wyzwala to ostrzeżenie, niekoniecznie jest zły), ponieważ wierzę w pracę z moimi narzędziami, a nie przeciwko nim. Jeśli gcc mówi mi, że nie może zoptymalizować kodu pod kątem sposobu, w jaki go napisałem, powinienem spojrzeć na przepisanie go. Podejrzewam, że kod, który wyzwala to ostrzeżenie, mógłby skorzystać na byciu bardziej modułowym, niezależnie od tego, więc chociaż kod nie jest technicznie zły (prawdopodobnie), stylistycznie prawdopodobnie jest.

  • -Wfloat-equalostrzega przed bezpiecznymi porównaniami równości (w szczególności porównanie z nieobliczoną wartością -1). Przykładem w moim kodzie, w którym używam tego, jest to, że mam wektor typu float. Przechodzę przez ten wektor i są pewne elementy, których nie mogę jeszcze ocenić, jakie powinny być, więc ustawiam je na -1.0f (ponieważ mój problem wykorzystuje tylko liczby dodatnie, -1 jest poza domeną). Później sprawdzam i aktualizuję wartości -1.0f. Niełatwo nadaje się do innej metody działania. Podejrzewam, że większość ludzi nie ma tego problemu, a porównanie dokładnej liczby w liczbach zmiennoprzecinkowych jest prawdopodobnie błędem, więc umieszczam go na liście domyślnej.

  • -Wold-style-castma wiele fałszywych alarmów w kodzie biblioteki, którego używam. W szczególności rodzina funkcji htonl używanych w sieci, a także implementacja szyfrowania Rijndael (AES), której używam, ma rzuty starego stylu, o których ostrzega mnie. Zamierzam wymienić oba te elementy, ale nie jestem pewien, czy w moim kodzie jest coś jeszcze, na co będzie narzekał. Jednak większość użytkowników prawdopodobnie powinna mieć to domyślnie włączone.

  • -Wsign-conversionbył trudny (i prawie nie znalazł się na liście). Włączenie go w moim kodzie wygenerowało ogromną ilość ostrzeżeń (ponad 100). Prawie wszyscy byli niewinni. Jednak starałem się używać liczb całkowitych ze znakiem wszędzie tam, gdzie nie byłem pewien, chociaż w przypadku mojej konkretnej domeny problemowej zwykle uzyskiwałbym niewielki wzrost wydajności przy użyciu wartości bez znaku z powodu dużej ilości dzielenia liczb całkowitych, które robię. Poświęciłem tę wydajność, ponieważ obawiałem się przypadkowego przekształcenia liczby całkowitej ze znakiem na liczbę bez znaku, a następnie dzielenia (co nie jest bezpieczne, w przeciwieństwie do dodawania, odejmowania i mnożenia). Włączenie tego ostrzeżenia pozwoliło mi bezpiecznie zmienić większość moich zmiennych na typy bez znaku i dodać kilka rzutów w innych miejscach. Obecnie jest trochę trudny w użyciu, ponieważ ostrzeżenie nie jest tak inteligentne. Na przykład, jeśli to zrobiszunsigned short + (integral constant expression), ten wynik jest niejawnie promowany do int. Następnie ostrzega o potencjalnym problemie ze znakiem, jeśli przypiszesz tę wartość do unsignedlub unsigned short, nawet jeśli jest to bezpieczne. Jest to zdecydowanie najbardziej opcjonalne ostrzeżenie dla prawie wszystkich użytkowników.

  • -Wsign-promo: patrz -Wsign-conversion.

  • -Wswitch-defaultwydaje się bezcelowe (nie zawsze chcesz domyślnego przypadku, jeśli wyraźnie wyliczyłeś wszystkie możliwości). Jednak włączenie tego ostrzeżenia może wymusić coś, co prawdopodobnie jest dobrym pomysłem. W przypadkach, w których jawnie chcesz zignorować wszystko oprócz wymienionych możliwości (ale możliwe są inne liczby), wpiszdefault: break;aby było to wyraźne. Jeśli wyraźnie wyliczysz wszystkie możliwości, włączenie tego ostrzeżenia pomoże upewnić się, że umieścisz coś w rodzaju assert (false), aby upewnić się, że faktycznie pokryłeś wszystkie możliwe opcje. Pozwala ci jasno określić domenę twojego problemu i wymusza to programowo. Musisz jednak zachować ostrożność, stosując wszędzie twierdzenie (fałsz). Jest to lepsze niż robienie niczego w przypadku domyślnego przypadku, ale jak zwykle w przypadku assert nie zadziała w kompilacjach wydań. Innymi słowy, nie możesz polegać na tym, aby sprawdzać liczby, które otrzymujesz, powiedzmy, z połączenia sieciowego lub bazy danych, nad którą nie masz całkowitej kontroli. Wyjątki lub wczesny powrót to najlepszy sposób na poradzenie sobie z tym (ale nadal wymagają domyślnego przypadku!).

  • -Werrorjest dla mnie ważna. Podczas kompilowania dużych ilości kodu w kompilacji wielowątkowej z wieloma elementami docelowymi łatwo jest prześlizgnąć się ostrzeżenie. Przekształcenie ostrzeżeń w błędy gwarantuje, że je zauważę.

Następnie jest zestaw ostrzeżeń, których nie ma na powyższej liście, ponieważ nie uważałem ich za przydatne. Oto ostrzeżenia i moje komentarze dotyczące tego, dlaczego nie umieszczam ich na domyślnej liście:

Ostrzeżenia, których nie ma:

  • -Wabinie jest potrzebne, ponieważ nie łączę plików binarnych z różnych kompilatorów. Mimo wszystko próbowałem z nim skompilować, ale to się nie uruchamia, więc nie wydaje się niepotrzebnie rozwlekłe.

  • -Waggregate-returnnie jest czymś, co uważam za błąd. Na przykład wyzwala się, gdy używana jest pętla for oparta na zakresie na wektorze klas. Optymalizacja wartości zwrotu powinna zająć się wszelkimi negatywnymi skutkami tego.

  • -Wconversionwyzwalacze w tym kodzie: short n = 0; n += 2;niejawna konwersja na int powoduje ostrzeżenie, gdy jest następnie konwertowana z powrotem na typ docelowy.

  • -Weffc++zawiera ostrzeżenie, jeśli wszyscy członkowie danych nie są zainicjowani na liście inicjatorów. W wielu przypadkach celowo tego nie robię, więc zestaw ostrzeżeń jest zbyt zagracony, aby był użyteczny. Pomocne jest jednak włączanie się od czasu do czasu i skanowanie w poszukiwaniu innych ostrzeżeń (takich jak niewirtualne destruktory klas podstawowych). Byłoby to bardziej przydatne jako zbiór ostrzeżeń (takich jak -Wall) zamiast pojedynczego ostrzeżenia.

  • -Winlinejest nieobecny, ponieważ nie używam słowa kluczowego inline do celów optymalizacji, tylko do definiowania funkcji w nagłówkach. Nie obchodzi mnie, czy optymalizator faktycznie go wstawia. To ostrzeżenie również narzeka, jeśli nie może wstawić funkcji zadeklarowanej w treści klasy (takiej jak pusty wirtualny destruktor).

  • -Winvalid-pch brakuje, ponieważ nie używam prekompilowanych nagłówków.

  • -Wmissing-format-attributenie jest używany, ponieważ nie używam rozszerzeń GNU. To samo dla -Wsuggest-attributei kilku innych

  • Potencjalnie godne uwagi jest jego nieobecność -Wno-long-long, której nie potrzebuję. Kompiluję z -std=c++0x( -std=c++11w GCC 4.7), który zawiera long longtypy całkowite. Ci, którzy utknęli w C ++ 98 / C ++ 03, mogą rozważyć dodanie tego wykluczenia z listy ostrzeżeń.

  • -Wnormalized=nfc jest już opcją domyślną i wygląda na najlepszą.

  • -Wpaddedjest czasami włączana, aby zoptymalizować układ klas, ale nie jest włączona, ponieważ nie wszystkie klasy mają wystarczającą liczbę elementów, aby na końcu usunąć dopełnienie. Teoretycznie mógłbym uzyskać dodatkowe zmienne za „bezpłatne”, ale nie jest to warte dodatkowego wysiłku, aby to utrzymać (jeśli rozmiar mojej klasy się zmieni, nie jest łatwo usunąć te wcześniej wolne zmienne).

  • -Wstack-protector nie jest używany, ponieważ nie używam -fstack-protector

  • -Wstrict-aliasing=3jest włączony przez -Walli jest najdokładniejszy, ale wygląda na to, że poziomy 1 i 2 dają więcej ostrzeżeń. Teoretycznie niższy poziom jest „silniejszym” ostrzeżeniem, ale odbywa się to kosztem większej liczby fałszywych alarmów. Mój własny kod testowy skompilowany czysto na wszystkich 3 poziomach.

  • -Wswitch-enumnie jest zachowaniem, którego chcę. Nie chcę jawnie obsługiwać każdej instrukcji przełącznika. Byłoby użyteczne, gdyby język miał jakiś mechanizm do aktywowania tego na określonych instrukcjach przełącznika (aby zapewnić, że przyszłe zmiany w wyliczeniu są obsługiwane wszędzie tam, gdzie są potrzebne), ale jest to przesada dla ustawienia typu „wszystko albo nic”.

  • -Wunsafe-loop-optimizationspowoduje zbyt wiele fałszywych ostrzeżeń. Przydatne może być okresowe stosowanie tego i ręczna weryfikacja wyników. Na przykład wygenerował to ostrzeżenie w moim kodzie, gdy wykonałem pętlę po wszystkich elementach w wektorze, aby zastosować do nich zestaw funkcji (używając pętli for opartej na zakresie). Jest to również ostrzeżenie dla konstruktora tablicy const składającej się z const std :: string (gdzie nie jest to pętla w kodzie użytkownika).

  • -Wzero-as-null-pointer-constanti -Wuseless-castsą tylko ostrzeżeniami GCC-4.7-only, które dodam, kiedy przejdę na GCC 4.7.

Złożyłem kilka zgłoszeń błędów / próśb o ulepszenia w gcc w wyniku niektórych z tych badań, więc mam nadzieję, że w końcu uda mi się dodać więcej ostrzeżeń z listy „nie uwzględniaj” do listy „uwzględnij” . Ta lista zawiera wszystkie ostrzeżenia wymienione w tym wątku (plus myślę, że kilka dodatkowych). Wiele ostrzeżeń, które nie zostały wyraźnie wymienione w tym poście, stanowią część innego ostrzeżenia, o którym wspominam. Jeśli ktoś zauważy ostrzeżenia, które są całkowicie wykluczone z tego postu, daj mi znać.

edycja: Wygląda na to, że przegapiłem kilka (które teraz dodałem). W rzeczywistości istnieje druga strona pod adresem http://gcc.gnu.org, która jest dość dobrze ukryta. Ogólne opcje ostrzeżeń i opcje C ++ (przewiń w dół, aby zobaczyć ostrzeżenia)


Niedawno przesłałem prośbę o ulepszenie na podstawie moich badań dla tej odpowiedzi: gcc.gnu.org/bugzilla/show_bug.cgi?id=53313 . Znacznie uprościłoby to sytuację ostrzegawczą, tworząc poziomy ostrzegawcze. W mojej propozycji mój sugerowany zestaw ostrzeżeń to w przybliżeniu -W4, z dodatkową propozycją utworzenia -Winf, co oznaczałoby -Wszystko-i-naprawdę-to-znaczy-tym-razem
David Stone

Prośba o ulepszenie, która spowodowałaby dodanie części -Wpadded do listy polecanych: gcc.gnu.org/bugzilla/show_bug.cgi?id=53514
David Stone

Żądanie ulepszenia, które spowodowałoby dodanie części -Weffc ++ do listy zalecanych: gcc.gnu.org/bugzilla/show_bug.cgi?id=16166
David Stone

1
@Predelnik: To trudniejsze. -Wswitch-enumostrzega, jeśli nie obsłużysz jawnie każdej wartości wyliczenia w przełączniku i defaultnie jest liczona jako jawna. Z drugiej strony -Wswitch-defaultostrzega, jeśli twój przełącznik nie ma defaultprzypadku, nawet jeśli wyraźnie zakryłeś wszystkie możliwe wartości.
David Stone

2
BTW - użyj -isystemzamiast -I„starego kodu biblioteki”, aby zapobiec tym wszystkim fałszywym
trafom

39

D'oh, wszystkie moje oryginalne wyszukiwania doprowadziły do ​​99% postów na temat tłumienia ostrzeżeń (wystarczająco przerażająco), ale właśnie natknąłem się na ten komentarz , który ma ten piękny zestaw flag (niektóre mniej istotne):

Sprawdzono krzyżowo z:

http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html

-g -O -Wall -Weffc++ -pedantic  \
-pedantic-errors -Wextra -Waggregate-return -Wcast-align \
-Wcast-qual -Wconversion \
-Wdisabled-optimization \
-Werror -Wfloat-equal -Wformat=2 \
-Wformat-nonliteral -Wformat-security  \
-Wformat-y2k \
-Wimplicit  -Wimport  -Winit-self  -Winline \
-Winvalid-pch   \
-Wlong-long \
-Wmissing-field-initializers -Wmissing-format-attribute   \
-Wmissing-include-dirs -Wmissing-noreturn \
-Wpacked  -Wpadded -Wpointer-arith \
-Wredundant-decls \
-Wshadow -Wstack-protector \
-Wstrict-aliasing=2 -Wswitch-default \
-Wswitch-enum \
-Wunreachable-code -Wunused \
-Wunused-parameter \
-Wvariadic-macros \
-Wwrite-strings

Myślę więc, że to dobry punkt wyjścia. Nie zdawałem sobie sprawy, że to oszustwo, ale przynajmniej było głęboko zakopane. :-)


1
Być może, ale wydaje się, że zmienia się to między wersjami, i prawdopodobnie z powodu kaprysu plam słonecznych i RMS, więc zbyt wyraźne wyrażanie prawdopodobnie nie zaszkodzi. W każdym razie to dobry punkt wyjścia.
Sdaz MacSkibbons

3
Z szybkiego grepa 4.5.2 c-opts.c / opts.c dla 'case OPT_W' brakuje: ścisłego przepełnienia, undef, ścisłego wartownika nul, znormalizowanego, multichar, niejawnej deklaracji funkcji, deprecated, endif labels, komentarz s , przedefiniowane wbudowane makro, większe niż, większe niż eq, abi. To szalone, że nie ma opcji wiersza poleceń, aby je wyświetlić.
Tony Delroy

3
Myślę, że to bardziej szalone, że -Wallnie robi tego, czego można by się spodziewać. Ale dziękuję, niektóre z nich wyglądają na bardzo przydatne!
Sdaz MacSkibbons

1
Wyłączenie ostrzeżeń ma swoje miejsce. W końcu są to „ostrzeżenia”. Inna sytuacja ma miejsce, gdy włączysz flagę, która włącza wiele ostrzeżeń, ale chcesz być selektywny.
Tamás Szelei

1
Jak możesz używać -Waggregate-return? To daje mi ostrzeżenie przy każdym użyciubegin/end()
Flamefire

13

Niektóre z nich są już uwzględnione w -Walllub -Wextra.

Dobra konfiguracja podstawowa dla C to:

-std=c99 -pedantic -Wall -Wextra -Wwrite-strings -Werror

i dla C ++

-ansi -pedantic -Wall -Wextra -Weffc++

(pomijanie -Werrordla C ++, ponieważ -Weffc++ma pewne irytujące)


10
Można -Werror być wyłączone dla określonych typów ostrzeżeń, na przykład: -Werror -Weffc ++ -Wno-error = effc ++
Robert Hensing

2
ansi : W trybie C jest to równoważne -std=c89. W trybie C ++ jest odpowiednikiem -std=c++98. tzn. jeśli podajesz inne std, nie używajansi
Sean Breckenridge

2

Próbować

export CFLAGS="`gcc --help=warnings | grep '\-W' | awk '{print $1 \" \"}' |
sort | uniq` -pedantic -fdiagnostics-show-option -Werror"

To szybki i brudny początek, który z pewnością będzie wymagał dostrojenia; po pierwsze, nawet jeśli wywołasz kompilator odpowiednią nazwą dla swojego języka (np. g++dla C ++), otrzymasz ostrzeżenia, które nie mają zastosowania do tego języka (a kompilator wzniesie ręce i odmówi kontynuowania, dopóki usuń ostrzeżenie).

Inna sprawa, że ​​dodałem -Werror, bo jeśli nie naprawiasz ostrzeżeń, dlaczego zależy ci na ich włączeniu? Możesz także usunąć ostrzeżenia z listy. (Na przykład prawie nigdy nie używam -Waggregate-returnz C ++.)

Niektóre ostrzeżenia nic nie dadzą bez innych opcji związanych z wydajnością ( -Wstack-protector). -fdiagnostics-show-optioni podręcznik GCC są twoimi przyjaciółmi.

Nawiasem mówiąc, niektóre ostrzeżenia wykluczają się wzajemnie; w szczególności używanie -Wtraditionali -Wold-style-definitionwraz z -Werror, nie będzie się kompilować.


0

W pliku CmakeLists.txt mojego Cliona

cmake_minimum_required(VERSION 3.13)
project(cpp17)

set(CMAKE_CXX_STANDARD 17)

set(GCC_COVERAGE_COMPILE_FLAGS "-std=c++17 -Wall -Weffc++ -Wno-error=effc++ -pedantic \
 -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-newline-eof  \
-pedantic-errors -Wextra -Waggregate-return -Wcast-align \
-Wcast-qual -Wconversion \
-Wdisabled-optimization \
-Werror -Wfloat-equal -Wformat=2 \
-Wformat-nonliteral -Wformat-security  \
-Wformat-y2k \
-Wimplicit  -Wimport  -Winit-self  -Winline -Winvalid-pch   \
-Wlong-long \
-Wmissing-field-initializers -Wmissing-format-attribute   \
-Wmissing-include-dirs -Wmissing-noreturn \
-Wpacked  -Wpadded -Wpointer-arith \
-Wredundant-decls \
-Wshadow -Wstack-protector \
-Wstrict-aliasing=2 -Wswitch-default \
-Wswitch-enum \
-Wunreachable-code -Wunused \
-Wunused-parameter \
-Wvariadic-macros \
-Wwrite-strings")


set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}" )

add_executable(cpp17 main.cpp)
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.