Jako programista C & Objective-C jestem trochę paranoikiem przy flagach ostrzegawczych kompilatora.
Zwykle staram się znaleźć pełną listę flag ostrzegawczych dla kompilatora, którego używam, i włączam większość z nich, chyba że mam naprawdę dobry powód, aby go nie włączać.
Osobiście uważam, że może to faktycznie poprawić umiejętności kodowania, a także potencjalną przenośność kodu, zapobiec niektórym problemom, ponieważ zmusza cię do bycia świadomym każdego najmniejszego szczegółu, potencjalnych problemów związanych z implementacją i architekturą itp.
Moim zdaniem jest to również dobre narzędzie do nauki na co dzień, nawet jeśli jesteś doświadczonym programistą.
W subiektywnej części tego pytania chciałbym usłyszeć innych programistów (głównie C, Objective-C i C ++) na ten temat.
Czy naprawdę obchodzą Cię takie rzeczy, jak ostrzeżenia pedantyczne itp.? A jeśli tak lub nie, dlaczego?
Jeśli chodzi o Objective-C, niedawno całkowicie przełączyłem się na zestaw narzędzi LLVM (z Clang), zamiast GCC.
W moim kodzie produkcyjnym zwykle ustawiam te flagi ostrzegawcze (wyraźnie, nawet jeśli niektóre z nich mogą być objęte przez -Wall):
- -Ściana
- -Wbad-obsada funkcji
- -Wyrównanie emisji
- Konwersja
- -Deklaracja po deklaracji
- -Wdeprecated-implementations
- -Wextra
- - Równe na powierzchni
- -Wformat = 2
- -Format-nieliteralny
- -Wour-char-constans
- -Wproste-atomowe-właściwości
- -Brakujące szelki
- -Brak deklaracji
- -Inicjalizatory pola brakującego
- -Wiss-format-atrybut
- -Brak-niewiedzy
- -Missy-prototypy
- -Wewnętrzne ogniki
- -Weewline-eof
- - Definicja w starym stylu
- -Szeroki-struny
- -Dziecie
- -Winter-arith
- -Wedundant-decls
- -Tylko zwrotny
- -Punkt konsekwencji
- -Cień
- -Wshorten-64-do-32
- -Zapisz-porównaj
- Konwersja znaku
- -Silne prototypy
- -Silne dopasowanie selektora
- -Wswitch
- -Wswitch-default
- -Wswitch-enum
- -Wundeclared-selektor
- -Zainicjowano
- -Wownnown-pragmas
- -Wunreachable-code
- -Zużyta funkcja
- -Nieużywane-etykieta
- -Zużyty parametr
- -Niewykorzystana wartość
- -Wunused-zmienna
- -Zapisz ciągi
Chciałbym poznać opinie innych programistów na ten temat.
Na przykład, czy myślisz, że przegapiłem konkretną flagę dla Clanga (Objective-C) i dlaczego?
A może uważasz, że konkretna flaga nie jest przydatna (lub wcale nie jest pożądana) i dlaczego?
EDYTOWAĆ
Aby wyjaśnić pytanie, zwróć uwagę, że -Wall
zawiera tylko kilka podstawowych ostrzeżeń.
W rzeczywistości są to o wiele więcej flag ostrzegawczych, których nie obejmuje -Wall
, stąd pytanie i lista, którą przedstawiam.
źródło
-Wwrite-strings
sprawia , że jest to kompilator języka bardzo podobnego, ale nie do końca C. Z tego powodu nie używam tej opcji. Inne niż te, które określiłeś, używam-pedantic -Wstrict-overflow=5 -Winline -Wundef -Wcast-qual -Wlogical-op -Wstrict-aliasing=2
i-Wno-missing-braces -Wno-missing-field-initializers
dla idealnie rozsądnego inicjalizatorastruct whatever obj = {0};
. Uważam również, że-Wconversion
daje więcej „spamu” niż przydatnych ostrzeżeń :)Odpowiedzi:
Dla kontekstu jestem programistą Clang pracującym w Google. W Google wdrożyliśmy diagnostykę Clanga (zasadniczo) dla wszystkich naszych programistów C ++ i traktujemy ostrzeżenia Clanga również jako błędy. Jako zarówno programista Clang, jak i jeden z większych użytkowników diagnostyki Clanga, postaram się rzucić nieco światła na te flagi i sposób ich użycia. Zauważ, że wszystko, co opisuję, ogólnie dotyczy Clanga, a nie specyficzne dla C, C ++ lub Objective-C.
TL; DR wersja: Proszę używać
-Wall
i-Werror
co najmniej na każdym nowym kodzie rozwijają. My (programiści kompilatora) dodajemy tutaj ostrzeżenia z ważnych powodów: znajdują błędy. Jeśli znajdziesz ostrzeżenie, które wyłapuje błędy, włącz je również. Wypróbuj-Wextra
tutaj grupę dobrych kandydatów. Jeśli jeden z nich jest zbyt głośny, abyś mógł z niego korzystać, zgłoś błąd . Jeśli piszesz kod zawierający „oczywisty” błąd, ale kompilator go nie ostrzega, zgłoś błąd.Teraz do długiej wersji. Najpierw trochę informacji na temat grupowania flag ostrzegawczych. Istnieje wiele „grup” ostrzeżeń w Clang (i w ograniczonym zakresie w GCC). Niektóre z nich są istotne w tej dyskusji:
-Wall
: Są to ostrzeżenia, że programiści mają wysokie zaufanie zarówno do ich wartości, jak i niskiego wskaźnika fałszywie dodatnich.-Wextra
: Są to ostrzeżenia, które są uważane za wartościowe i solidne (tzn. Nie są błędne), ale mogą mieć wysokie wskaźniki fałszywie dodatnich lub wspólne obiekcje filozoficzne.-Weverything
: To szalona grupa, która dosłownie włącza każde ostrzeżenie w Clang. Nie używaj tego w swoim kodzie. Jest przeznaczony wyłącznie dla programistów Clanga lub do zbadania istniejących ostrzeżeń .Istnieją dwa podstawowe kryteria wspomniane powyżej, które kierują ostrzeżeniami w Clang i wyjaśnijmy, co one naprawdę oznaczają. Pierwszą jest potencjalna wartość konkretnego wystąpienia ostrzeżenia. Jest to oczekiwana korzyść dla użytkownika (programisty), gdy ostrzeżenie zostanie uruchomione i poprawnie zidentyfikuje problem z kodem.
Drugim kryterium jest idea fałszywie pozytywnych raportów. Są to sytuacje, w których ostrzeżenie jest uruchamiane w kodzie, ale potencjalny cytowany problem w rzeczywistości nie występuje z powodu kontekstu lub innych ograniczeń programu. Ostrzegany kod faktycznie zachowuje się poprawnie. Są one szczególnie złe, gdy ostrzeżenie nigdy nie było przeznaczone do uruchomienia dla tego wzorca kodu. Zamiast tego jest to brak implementacji ostrzeżenia, który powoduje, że tam strzela.
W przypadku ostrzeżeń Clanga wartość musi być zgodna z poprawnością , a nie ze stylem, smakiem czy konwencjami kodowania. Ogranicza to zestaw dostępnych ostrzeżeń, wykluczając często
{}
pojawiające się ostrzeżenia, takie jak ostrzeżenie, ilekroć nie są używane w treściif
instrukcji. Clang jest również bardzo nietolerancyjny w stosunku do fałszywych alarmów . W przeciwieństwie do większości innych kompilatorów użyje niewiarygodnej różnorodności źródeł informacji do przycinania fałszywych trafień, w tym dokładnej pisowni konstruktu, obecności lub braku dodatkowych „()”, rzutowań, a nawet makr preprocesora!Teraz weźmy kilka przykładowych ostrzeżeń z rzeczywistego świata od Clanga i zobaczmy, jak są one podzielone na kategorie. Po pierwsze, domyślne ostrzeżenie:
Tutaj nie była wymagana flaga, aby otrzymać to ostrzeżenie. Uzasadnieniem jest to, że ten kod nigdy nie jest naprawdę poprawny, co daje ostrzeżenie o wysokiej wartości , a ostrzeżenie jest uruchamiane tylko w kodzie, który Clang może udowodnić, że wpada do tego segmentu, dając mu zerową częstość fałszywie dodatnich .
Clang wymaga
-Wall
flagi dla tego ostrzeżenia. Powodem jest to, że istnieje nietrywialna ilość kodu, który wykorzystał (na dobre lub złe) wzorzec kodu, o którym ostrzegamy, aby celowo wygenerować niezainicjowaną wartość. Filozoficznie nie widzę w tym sensu, ale wielu innych się nie zgadza, a rzeczywistość tej różnicy zdań jest tym, co napędza ostrzeżenie pod-Wall
flagą. Nadal ma bardzo wysoką wartość i bardzo niski odsetek wyników fałszywie dodatnich , ale w niektórych bazach kodowych nie jest on uruchamiany.To ostrzeżenie wymaga
-Wextra
flagi. Powodem jest to, że istnieją bardzo duże bazy kodu, w których źle dobrany znak w porównaniu jest niezwykle powszechny. Chociaż to ostrzeżenie zawiera pewne błędy, prawdopodobieństwo, że kod jest błędem, gdy użytkownik pisze, jest średnio dość niskie. Rezultatem jest wyjątkowo wysoki odsetek wyników fałszywie dodatnich . Jednak gdy w programie występuje błąd z powodu dziwnych zasad promocji, często jest bardzo subtelny, dlatego ostrzeżenie, gdy oznacza błąd, ma stosunkowo wysoką wartość . W rezultacie Clang zapewnia go i wystawia pod flagą.Zazwyczaj ostrzeżenia nie żyją długo poza
-Wextra
flagą. Clang bardzo stara się nie wdrażać ostrzeżeń, które nie są regularnie używane i testowane. Dodatkowe ostrzeżenia włączane przez-Weverything
są zwykle ostrzeżeniami w trakcie aktywnego opracowywania lub z aktywnymi błędami. Albo zostaną ustalone i umieszczone pod odpowiednimi flagami, albo powinny zostać usunięte.Teraz, gdy rozumiemy, jak te rzeczy działają z Clangiem, spróbujmy wrócić do pierwotnego pytania: jakie ostrzeżenia powinieneś włączyć w swoim rozwoju? Odpowiedź brzmi niestety, że to zależy. Rozważ następujące pytania, aby ustalić, które ostrzeżenia najlepiej pasują do Twojej sytuacji.
Przede wszystkim, jeśli nie kontrolujesz kodu, nie próbuj włączać dodatkowych ostrzeżeń. Przygotuj się na wyłączenie niektórych. Na świecie jest wiele złych kodów i możesz nie być w stanie naprawić wszystkich. To dobrze. Pracuj, aby znaleźć sposób, aby skoncentrować swoje wysiłki na kodzie, który kontrolujesz.
Następnie dowiedz się, czego chcesz z ostrzeżeń. To jest różne dla różnych ludzi. Clang spróbuje ostrzec bez żadnych rażących błędów lub wzorców kodu, dla których mamy długą historyczną precedens wskazujący, że wskaźnik błędów jest wyjątkowo wysoki. Umożliwiając
-Wall
otrzymanie o wiele bardziej agresywnego zestawu ostrzeżeń mających na celu wychwycenie najczęstszych błędów, które deweloperzy Clang zaobserwowali w kodzie C ++. Ale w obu przypadkach odsetek wyników fałszywie dodatnich powinien pozostać dość niski.Wreszcie, jeśli jesteś całkowicie gotów uciszyć * fałszywie dodatnie * za każdym razem, idź
-Wextra
. Zgłaszaj błędy, jeśli zauważysz ostrzeżenia, które wyłapują wiele prawdziwych błędów, ale które mają głupie lub bezcelowe fałszywe alarmy. Nieustannie pracujemy, aby znaleźć sposoby, aby przynieść więcej i więcej logiki błędów obecnych w rozpoznawczej-Wextra
w-Wall
którym możemy uniknąć fałszywych alarmów.Wielu przekona się, że żadna z tych opcji nie jest dla nich odpowiednia. W Google
-Wall
wyłączyliśmy niektóre ostrzeżenia z powodu dużej ilości istniejącego kodu, który naruszył ostrzeżenie. Włączyliśmy też jawnie niektóre ostrzeżenia, nawet jeśli nie są one włączone-Wall
, ponieważ mają dla nas szczególnie wysoką wartość. Twój przebieg będzie się różnić, ale prawdopodobnie będzie się różnić w podobny sposób. Często lepiej jest włączyć kilka kluczowych ostrzeżeń niż wszystkie-Wextra
.Zachęcam wszystkich do włączenia
-Wall
dowolnego nie-starszego kodu. W przypadku nowego kodu ostrzeżenia tutaj są prawie zawsze cenne i naprawdę ułatwiają tworzenie kodu. I odwrotnie, zachęcam wszystkich, aby nie włączali flag poza nimi-Wextra
. Jeśli znajdziesz ostrzeżenie Clanga, które-Wextra
nie obejmuje, ale które okazuje się dla ciebie cenne, po prostu zgłoś błąd, a my prawdopodobnie możemy go zaliczyć-Wextra
. To, czy jawnie włączysz jakiś podzbiór ostrzeżeń,-Wextra
będzie w dużym stopniu zależeć od twojego kodu, twojego stylu kodowania i od tego, czy utrzymanie tej listy jest łatwiejsze niż naprawianie wszystkiego, co nie zostało odkryte-Wextra
.Z listy ostrzeżeń PO (która zawiera oba
-Wall
i-Wextra
) tylko następujące ostrzeżenia nie są objęte tymi dwiema grupami (lub domyślnie włączone). Pierwsza grupa podkreśla, dlaczego nadmierne poleganie na wyraźnych flagach ostrzegawczych może być złe: żadna z nich nie jest nawet zaimplementowana w Clang! Są akceptowane w wierszu poleceń tylko ze względu na zgodność z GCC.-Wbad-function-cast
-Wdeclaration-after-statement
-Wmissing-format-attribute
-Wmissing-noreturn
-Wnested-externs
-Wnewline-eof
-Wold-style-definition
-Wredundant-decls
-Wsequence-point
-Wstrict-prototypes
-Wswitch-default
Następna grupa niepotrzebnych ostrzeżeń z oryginalnej listy to te, które są zbędne z innymi na tej liście:
-Wformat-nonliteral
-- Podzbiór-Wformat=2
-Wshorten-64-to-32
-- Podzbiór-Wconversion
-Wsign-conversion
-- Podzbiór-Wconversion
Istnieje również wybór ostrzeżeń, które są bardziej kategorycznie różne. Mają one do czynienia z wariantami dialektów językowych, a nie z błędnym lub niepoprawnym kodem. Z wyjątkiem
-Wwrite-strings
tych, wszystkie są ostrzeżeniami dla rozszerzeń języka dostarczanych przez Clang. To, czy Clang ostrzega przed ich użyciem, zależy od rozpowszechnienia rozszerzenia. Clang dąży do kompatybilności z GCC, a więc w wielu przypadkach ułatwia to dzięki niejawnym rozszerzeniom języka, które są szeroko stosowane.-Wwrite-strings
, jak skomentował OP, to flaga zgodności z GCC, która faktycznie zmienia semantykę programu. Głęboko żałuję tej flagi, ale musimy ją poprzeć ze względu na jej dziedzictwo.-Wfour-char-constants
-Wpointer-arith
-Wwrite-strings
Pozostałe opcje, które faktycznie umożliwiają potencjalnie interesujące ostrzeżenia, to:
-Wcast-align
-Wconversion
-Wfloat-equal
-Wformat=2
-Wimplicit-atomic-properties
-Wmissing-declarations
-Wmissing-prototypes
-Woverlength-strings
-Wshadow
-Wstrict-selector-match
-Wundeclared-selector
-Wunreachable-code
Powód, dla którego ich nie ma
-Wall
lub-Wextra
nie zawsze jest jasny. Dla wielu z nich, są one faktycznie na podstawie ostrzeżeń (GCC-Wconversion
,-Wshadow
itp) i jako takie Clang próbuje naśladować zachowania GCC. Powoli dzielimy niektóre z nich na bardziej szczegółowe i przydatne ostrzeżenia. Ci mają większe prawdopodobieństwo, że znajdą się w jednej z grup ostrzegawczych najwyższego poziomu. To powiedziawszy, aby wybrać jedno ostrzeżenie,-Wconversion
jest tak szerokie, że prawdopodobnie pozostanie własną kategorią „najwyższego poziomu” w dającej się przewidzieć przyszłości. Niektóre inne ostrzeżenia, które GCC ma, ale które mają niską wartość i wysokie wskaźniki fałszywie dodatnich, mogą zostać przeniesione na podobną ziemię niczyją.Inne powody, dla których nie ma ich w jednym z większych koszyków, to proste błędy, bardzo znaczące fałszywie pozytywne problemy i ostrzeżenia w trakcie opracowywania. Zajmę się zgłaszaniem błędów dla tych, które mogę zidentyfikować. Wszyscy powinni ostatecznie migrować do odpowiedniej flagi dużego wiadra lub zostać usunięci z Clang.
Mam nadzieję, że to wyjaśnia sytuację ostrzegawczą z Clangiem i zapewnia pewien wgląd dla tych, którzy próbują wybrać zestaw ostrzeżeń dla ich zastosowania lub użytkowania ich firmy.
źródło
-Wno
konieczności wyłączaniawarn_no_constructor_for_refconst
powoduje, że PITA używa Boost.ConceptCheck i podobnie: github.com/boostorg/concept_check/blob/…Nie używam Clanga, ale mam nadzieję, że nie będziesz miał nic przeciwko, aby mieć moją opinię. Idę też z maksymalnym poziomem ostrzegania (zakładam, że to właśnie oznacza -Wall) i traktuję ostrzeżenia jako błędy (zakładam, że to oznacza -Werror) i wyłączam tylko te kilka ostrzeżeń, które nie mają większego sensu. W rzeczywistości denerwuje mnie fakt, że kompilator C # nie emituje pewnych bardzo użytecznych ostrzeżeń i aby je zobaczyć, trzeba uruchomić specjalne narzędzia do analizy kodu. Lubię ostrzeżenia, ponieważ pomagają mi wychwycić małe błędy i błędy w moim kodzie. Lubię je tak bardzo, że kiedy ostrzeżenie jest wydawane dla fragmentu kodu, który według mnie jest poprawny, i tak refaktoryzuję ten fragment kodu, aby ostrzeżenie nie zostało wydane, zamiast wyłączać ostrzeżenie lub - nawet gorzej - pozwól mu się pojawić i zignoruj to. Myślę, że ostrzeżenia są niesamowite,
źródło
-Wall
zawiera tylko podstawowe ostrzeżenia. Wiele istniejących flag ostrzegawczych nie jest objętych-Wall
, stąd lista w moim pytaniu.Zazwyczaj korzystam z domyślnych ustawień Xcode dla nowego projektu; zapewnia dobrą równowagę między pomocnością a irytacją. Każda konkretna lista ostrzeżeń i inne opcje kompilatora będą w dużej mierze oparte na osobistych preferencjach lub wymaganiach projektowych, więc nie sądzę, aby próba przeglądania twojej listy i argumentowania za konkretnymi ostrzeżeniami była jakaś wartość. Jeśli to działa, świetnie. Jeśli stwierdzisz, że popełniłeś błąd, który powinien być w stanie wykryć kompilator, i potrzebujesz pomocy w przyszłości, poszukaj opcji kompilatora, aby o tym ostrzec i włączyć go.
Jedną rzeczą, którą wielu programistów zaleca, jest włączenie opcji „Traktuj ostrzeżenia jako błędy” (-Werror), aby uniemożliwić pomyślne zakończenie kompilacji, jeśli pojawią się jakieś ostrzeżenia.
źródło
-Werror
. Faktycznie, jak używam dzyń, ustawić wszystkie te ostrzeżenia z wykorzystaniem pragma (#pragma dzyń diagnostyczny) i są one ustawione na błędy krytyczne, więc to jest takie samo jak-Werror
:)Myślę, że najlepszym dowodem na to, że ludziom zależy na ostrzeżeniach, jest fakt, że istnieją i są powszechnie używane. Jestem przekonany, że im więcej błędów wykryje się podczas kompilacji, tym lepiej. Gdyby nie było to powszechne przekonanie, wszyscy używaliby słabych, dynamicznie pisanych języków, ponieważ ich kompilatory lub tłumacze dają ci większą swobodę. Przeciwnie, nawet w językach skryptowych
strict
popularne jest stosowanie flag. W statycznych językach silnie typowanych ludzie nie tylko-Wall -Werror
często używają , ale często uważają, że ostrzeżenia są tak cenne, że chcą jeszcze więcej , więc płacą za narzędzia analizy statycznej, takie jak Coverity, których jedynym celem jest dostarczanie ostrzeżeń.To nie znaczy, że nie ma krytyków. Wielu programistów postrzega ostrzeżenia jako działające przeciwko nim w perspektywie krótkoterminowej, a nie pracujące dla nich w perspektywie długoterminowej, i nie próbują naprawić podstawowego problemu. Dlatego widzisz piękny kod, taki jak ten fragment, który natknąłem się wczoraj:
źródło
-Werror
i ignorujących ostrzeżenia wydawane przez kompilator. A jeśli tak, po prostu zwykle się trzymają-Wall
. Większość flag, które podam w swoim pytaniu, nie jest objęta-Wall
i osobiście uważam, że są one również niezbędne. Więc jestem po prostu paranoikiem? ; )Ogólnie rzecz biorąc, bardziej pochylam się w kierunku -Wall i zdecydowanie wierzę także w włączenie -Werror. Moduł nigdy nie powinien oczekiwać ostrzeżeń. W końcu dostaniesz kolejne ostrzeżenie i przegapisz je. I to będzie problem.
Zależy to również od tego, czy dodajesz „-Wall -Werror” do nowego czy starego projektu. Jeśli jest nowy, wybierz go i wymagaj doskonałości, w przeciwnym razie prawdopodobnie będziesz mieć dni lub tygodnie edycji i testowania. Właśnie to zrobiłem przy nieco nieco starszym projekcie i spędziłem dwa lub trzy dni na usuwaniu ostrzeżeń. Myślę, że kod jest teraz czystszy.
Innymi słowy, spróbuj i zobacz.
Niespokojny
źródło
-Wall
i-Werror
myślę, że powinieneś ponownie przeczytać pytanie. Wiele flag ostrzegawczych nie jest objętych-Wall
. W każdym razie dzięki za odpowiedź.