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ż, -Werror
jeś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).
-Wall
) jest-Wbloody_everything
flaga :-)-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-Weverything
jest prawdopodobnie najlepszym sposobem na odkrycie potencjalnie przydatnych ostrzeżeń, o których wcześniej nie wiedziałeś.Odpowiedzi:
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-unused
ponieważ 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-optimization
wydaje 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-equal
ostrzega 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-cast
ma 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-conversion
był 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ść dounsigned
lubunsigned 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-default
wydaje 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!).-Werror
jest 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:
-Wabi
nie 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-return
nie 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.-Wconversion
wyzwalacze 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.-Winline
jest 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-attribute
nie jest używany, ponieważ nie używam rozszerzeń GNU. To samo dla-Wsuggest-attribute
i kilku innychPotencjalnie godne uwagi jest jego nieobecność
-Wno-long-long
, której nie potrzebuję. Kompiluję z-std=c++0x
(-std=c++11
w GCC 4.7), który zawieralong long
typy 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ą.-Wpadded
jest 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=3
jest włączony przez-Wall
i 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-enum
nie 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-optimizations
powoduje 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-constant
i-Wuseless-cast
są 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)
źródło
-Wswitch-enum
ostrzega, jeśli nie obsłużysz jawnie każdej wartości wyliczenia w przełączniku idefault
nie jest liczona jako jawna. Z drugiej strony-Wswitch-default
ostrzega, jeśli twój przełącznik nie madefault
przypadku, nawet jeśli wyraźnie zakryłeś wszystkie możliwe wartości.-isystem
zamiast-I
„starego kodu biblioteki”, aby zapobiec tym wszystkim fałszywymD'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
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. :-)
źródło
-Wall
nie robi tego, czego można by się spodziewać. Ale dziękuję, niektóre z nich wyglądają na bardzo przydatne!-Waggregate-return
? To daje mi ostrzeżenie przy każdym użyciubegin/end()
Niektóre z nich są już uwzględnione w
-Wall
lub-Wextra
.Dobra konfiguracja podstawowa dla C to:
-std=c99 -pedantic -Wall -Wextra -Wwrite-strings -Werror
i dla C ++
-ansi -pedantic -Wall -Wextra -Weffc++
(pomijanie
-Werror
dla C ++, ponieważ-Weffc++
ma pewne irytujące)źródło
-std=c89
. W trybie C ++ jest odpowiednikiem-std=c++98
. tzn. jeśli podajesz innestd
, nie używajansi
Próbować
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-return
z C ++.)Niektóre ostrzeżenia nic nie dadzą bez innych opcji związanych z wydajnością (
-Wstack-protector
).-fdiagnostics-show-option
i podręcznik GCC są twoimi przyjaciółmi.Nawiasem mówiąc, niektóre ostrzeżenia wykluczają się wzajemnie; w szczególności używanie
-Wtraditional
i-Wold-style-definition
wraz z-Werror
, nie będzie się kompilować.źródło
W pliku CmakeLists.txt mojego Cliona
źródło