Per il contesto, sono uno sviluppatore di Clang che lavora in Google. In Google, abbiamo implementato la diagnostica di Clang su (essenzialmente) tutti i nostri sviluppatori C ++ e trattiamo anche gli avvisi di Clang come errori. Come sia uno sviluppatore di Clang che uno dei maggiori utenti della diagnostica di Clang, proverò a far luce su queste bandiere e su come possono essere utilizzate. Nota che tutto ciò che sto descrivendo è genericamente applicabile a Clang e non specifico a C, C ++ o Objective-C.
TL; DR Versione: Si prega di utilizzare -Wall
e -Werror
come minimo su ogni nuovo codice che si sta sviluppando. Noi (gli sviluppatori del compilatore) aggiungiamo avvisi qui per buoni motivi: trovano bug. Se trovi un avviso che rileva i bug per te, attivalo pure. Prova qui -Wextra
un sacco di buoni candidati. Se uno di questi è troppo rumoroso per essere utilizzato in modo redditizio, invia un bug . Se scrivi un codice che contiene un bug "ovvio" ma il compilatore non ti ha avvisato, invia un bug.
Ora per la versione lunga. Prima alcuni retroscena sui raggruppamenti di bandiere di avvertimento. Ci sono molti "raggruppamenti" di avvertimenti in Clang (e in misura limitata nel GCC). Alcuni che sono rilevanti per questa discussione:
- Attivo per impostazione predefinita: questi avvisi sono sempre attivi, a meno che non vengano disabilitati esplicitamente.
-Wall
: Questi sono avvertimenti che gli sviluppatori hanno un'alta fiducia sia nel loro valore che in un basso tasso di falsi positivi.
-Wextra
: Si tratta di avvertimenti ritenuti preziosi e validi (ovvero non corretti), ma possono avere alti tassi di falsi positivi o obiezioni filosofiche comuni.
-Weverything
: Questo è un gruppo folle che abilita letteralmente ogni
avvertimento in Clang. Non usare questo sul tuo codice. È destinato esclusivamente agli sviluppatori Clang o all'esplorazione di quali avvisi esistono .
Ci sono due criteri principali sopra menzionati che guidano dove vanno gli avvisi a Clang, e chiariamo cosa significano veramente. Il primo è il valore potenziale
di una particolare occorrenza dell'avviso. Questo è il vantaggio atteso per l'utente (sviluppatore) quando viene generato l'avviso e
identifica correttamente un problema con il codice.
Il secondo criterio è l'idea di rapporti falsi positivi . Queste sono situazioni in cui l'avviso si attiva sul codice, ma il potenziale problema citato non si verifica in realtà a causa del contesto o di qualche altro vincolo del programma. Il codice avvisato in realtà si sta comportando correttamente. Questi sono particolarmente dannosi quando l'avviso non è mai stato progettato per attivare quel modello di codice. Invece, è una carenza nell'implementazione dell'avvertenza che lo fa sparare lì.
Per gli avvisi di Clang, il valore deve essere in termini di correttezza , non in termini di stile, gusto o convenzioni di codifica. Ciò limita la serie di avvisi disponibili, escludendo avvisi spesso richiesti come avvisi ogni volta {}
che non vengono utilizzati attorno al corpo di if
un'istruzione. Clang è anche molto intollerante ai falsi positivi . A differenza della maggior parte degli altri compilatori, utilizzerà un'incredibile varietà di fonti di informazioni per eliminare i falsi positivi, incluso l'ortografia esatta del costrutto, presenza o assenza di "()" extra, cast o persino macro di preprocessore!
Ora prendiamo alcuni avvertimenti di esempio del mondo reale di Clang e vediamo come sono classificati. Innanzitutto, un avviso predefinito:
% nl x.cc
1 class C { const int x; };
% clang -fsyntax-only x.cc
x.cc:1:7: warning: class 'C' does not declare any constructor to initialize its non-modifiable members
class C { const int x; };
^
x.cc:1:21: note: const member 'x' will never be initialized
class C { const int x; };
^
1 warning generated.
Qui non è stata richiesta la bandiera per ricevere questo avviso. La logica è che questo codice non è mai veramente corretto, dando l'avvertimento alto valore , e l'avvertimento si attiva solo sul codice che Clang può provare cade in questo bucket, dandogli un tasso zero di falsi positivi .
% nl x2.cc
1 int f(int x_) {
2 int x = x;
3 return x;
4 }
% clang -fsyntax-only -Wall x2.cc
x2.cc:2:11: warning: variable 'x' is uninitialized when used within its own initialization [-Wuninitialized]
int x = x;
~ ^
1 warning generated.
Clang richiede la -Wall
bandiera per questo avviso. Il motivo è che esiste una quantità non banale di codice che ha usato (nel bene o nel male) il modello di codice che stiamo avvertendo per produrre intenzionalmente un valore non inizializzato. Filosoficamente, non vedo alcun punto in questo, ma molti altri non sono d'accordo e la realtà di questa differenza di opinione è ciò che guida l'avvertimento sotto la
-Wall
bandiera. Ha ancora un valore molto alto e un tasso di falsi positivi molto basso
, ma su alcune basi di codice è un non-avviatore.
% nl x3.cc
1 void g(int x);
2 void f(int arr[], unsigned int size) {
3 for (int i = 0; i < size; ++i)
4 g(arr[i]);
5 }
% clang -fsyntax-only -Wextra x3.cc
x3.cc:3:21: warning: comparison of integers of different signs: 'int' and 'unsigned int' [-Wsign-compare]
for (int i = 0; i < size; ++i)
~ ^ ~~~~
1 warning generated.
Questo avviso richiede la -Wextra
bandiera. Il motivo è che ci sono
basi di codice molto grandi in cui il segno di corrispondenza errata nei confronti è estremamente comune. Mentre questo avviso rileva alcuni bug, la probabilità che il codice sia un bug quando l'utente lo scrive è in media abbastanza bassa. Il risultato è un tasso di falsi positivi estremamente elevato . Tuttavia, quando c'è un bug in un programma a causa delle strane regole di promozione, spesso è estremamente sottile dare questo avviso
quando segnala un bug ha un valore relativamente alto . Di conseguenza, Clang lo fornisce e lo espone sotto una bandiera.
In genere, gli avvisi non vivono a lungo al di fuori della -Wextra
bandiera. Clang si impegna a fondo per non implementare avvisi che non vedono un uso e test regolari. Gli avvisi aggiuntivi attivati -Weverything
sono in genere avvisi in fase di sviluppo attivo o con bug attivi. O saranno riparati e posizionati sotto le bandiere appropriate, o dovrebbero essere rimossi.
Ora che abbiamo capito come funzionano queste cose con Clang, proviamo a tornare alla domanda originale: quali avvertenze dovresti attivare per il tuo sviluppo? La risposta è, sfortunatamente, che dipende. Considera le seguenti domande per determinare quali avvisi funzionano meglio per la tua situazione.
- Hai il controllo su tutto il tuo codice o è in parte esterno?
- Quali sono i tuoi obiettivi? Catturare bug o scrivere codice migliore?
- Qual è la tua tolleranza ai falsi positivi? Desideri scrivere codice aggiuntivo per mettere a tacere gli avvisi su base regolare?
Innanzitutto, se non controlli il codice, non provare a attivare ulteriori avvisi. Preparati a spegnerne un po '. Esistono molti codici errati nel mondo e potresti non essere in grado di risolverli tutti. Va bene. Lavora per trovare un modo per concentrare i tuoi sforzi sul codice che controlli.
Quindi, capire cosa vuoi dai tuoi avvertimenti. Questo è diverso per persone diverse. Clang proverà ad avvisare senza alcuna opzione su bachi egregi, o modelli di codice per i quali abbiamo un precedente storico lungo che indica che la percentuale di bug è estremamente alta. Consentendo -Wall
di ottenere una serie molto più aggressiva di avvisi mirati a rilevare gli errori più comuni che gli sviluppatori di Clang hanno osservato nel codice C ++. Ma con entrambi i
tassi di falsi positivi dovrebbero rimanere piuttosto bassi.
Infine, se sei perfettamente disposto a mettere a tacere * falsi positivi * s ad ogni turno, procedi -Wextra
. File bug se noti avvisi che stanno rilevando molti bug reali, ma che hanno falsi positivi sciocchi o inutili. Lavoriamo costantemente per trovare modi per portare sempre più la logica di ricerca dei bug -Wextra
in -Wall
cui possiamo evitare i falsi positivi.
Molti scopriranno che nessuna di queste opzioni è giusta per loro. In Google, abbiamo disattivato alcuni avvisi a -Wall
causa di un sacco di codice esistente che ha violato l'avviso. Abbiamo anche attivato alcuni avvisi esplicitamente, anche se non sono abilitati da -Wall
, perché hanno un valore particolarmente elevato per noi. Il tuo chilometraggio varierà, ma probabilmente varierà in modi simili. Spesso può essere molto meglio abilitare alcuni avvisi chiave piuttosto che tutti
-Wextra
.
Vorrei incoraggiare tutti ad attivare -Wall
qualsiasi codice non legacy. Per il nuovo codice, gli avvisi qui sono quasi sempre preziosi e rendono davvero migliore l'esperienza di sviluppo del codice. Al contrario, incoraggerei tutti a
non abilitare le bandiere oltre -Wextra
. Se si trova un avvertimento Clang che -Wextra
non include, ma che si rivela affatto prezioso per voi, è sufficiente aprire un bug e possiamo probabilmente metterla sotto -Wextra
. L'abilitazione esplicita di alcuni sottoinsiemi degli avvisi -Wextra
dipenderà fortemente dal codice, dallo stile di codifica e dal fatto che mantenere tale elenco sia più semplice che correggere tutto ciò che viene scoperto -Wextra
.
Dell'elenco di avvisi del PO (che includeva entrambi -Wall
e -Wextra
) solo i seguenti avvisi non sono coperti da questi due gruppi (o attivati per impostazione predefinita). Il primo gruppo sottolinea perché l'eccessiva dipendenza dai flag di avvertimento espliciti può essere negativo: nessuno di questi è nemmeno implementato in Clang! Sono accettati dalla riga di comando solo per compatibilità 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
Il prossimo bucket di avvisi non necessari nell'elenco originale sono quelli che sono ridondanti con gli altri in tale elenco:
-Wformat-nonliteral
- Sottoinsieme di -Wformat=2
-Wshorten-64-to-32
- Sottoinsieme di -Wconversion
-Wsign-conversion
- Sottoinsieme di -Wconversion
Ci sono anche una selezione di avvisi che sono più categoricamente diversi. Si tratta di varianti del dialetto linguistico piuttosto che di codici errati o non corretti. Con l'eccezione di -Wwrite-strings
, tutti questi sono avvisi per le estensioni di lingua fornite da Clang. Se Clang avverte del loro uso dipende dalla prevalenza dell'estensione. Clang mira alla compatibilità GCC, e quindi in molti casi lo facilita con estensioni di linguaggio implicite che sono ampiamente utilizzate. -Wwrite-strings
, come commentato sull'OP, è un flag di compatibilità di GCC che modifica effettivamente la semantica del programma. Mi rammarico profondamente per questa bandiera, ma dobbiamo sostenerla a causa dell'eredità che ha ora.
-Wfour-char-constants
-Wpointer-arith
-Wwrite-strings
Le restanti opzioni che stanno effettivamente abilitando avvisi potenzialmente interessanti sono queste:
-Wcast-align
-Wconversion
-Wfloat-equal
-Wformat=2
-Wimplicit-atomic-properties
-Wmissing-declarations
-Wmissing-prototypes
-Woverlength-strings
-Wshadow
-Wstrict-selector-match
-Wundeclared-selector
-Wunreachable-code
Il motivo per cui questi non sono presenti -Wall
o -Wextra
non è sempre chiaro. Per molti di questi, sono in realtà basate su avvertimenti GCC ( -Wconversion
,
-Wshadow
, ecc) e come tale Clang cerca di imitare il comportamento di GCC. Stiamo lentamente suddividendo alcuni di questi in avvisi più dettagliati e utili. Quelli hanno quindi una maggiore probabilità di trasformarlo in uno dei gruppi di avvertimento di livello superiore. Detto questo, per cogliere un avvertimento, -Wconversion
è così ampio che probabilmente rimarrà la sua categoria di "livello superiore" per il prossimo futuro. Alcuni altri avvertimenti che GCC ha ma che hanno un basso valore e alti tassi di falsi positivi possono essere relegati in una terra di nessuno simile.
Altri motivi per cui questi non si trovano in uno dei bucket più grandi includono semplici bug, problemi falsi positivi molto significativi e avvisi di sviluppo. Esaminerò i bug di archiviazione per quelli che posso identificare. Dovrebbero infine migrare in una grande benna o essere rimossi da Clang.
Spero che questo chiarisca la situazione di avvertimento con Clang e fornisca alcuni spunti per coloro che cercano di scegliere una serie di avvisi per il loro uso o l'uso della loro azienda.