Utili flag GCC per C


157

Oltre all'impostazione -Walle all'impostazione -std=XXX, quali altri flag di compilatore davvero utili, ma meno noti, sono disponibili per l'uso in C?

Sono particolarmente interessato a eventuali avvisi aggiuntivi e / o e alla trasformazione di avvisi in errori in alcuni casi per ridurre al minimo qualsiasi discrepanza accidentale di tipo.


9
Bene -save-temps, -Wshadowed -fmudflaperano le più grandi scoperte che non conoscevo, grazie a tutti.
Matt Joiner,

Contesto, per quanto ne so: correre gcc -c [flags-go-here] -o myprog.o myprog.cper compilare (non collegare) un programma C.
Rory O'Kane,

Risposte:


64

Molte delle -fopzioni di generazione del codice sono interessanti:

  • La -ftrapvfunzione causerà l'interruzione del programma in caso di overflow di numeri interi con segno (formalmente "comportamento indefinito" in C).

  • -fverbose-asmè utile se stai compilando -Sper esaminare l'output dell'assemblaggio - aggiunge alcuni commenti informativi.

  • -finstrument-functions aggiunge il codice per chiamare le funzioni di profilazione fornite dall'utente in ogni punto di entrata e uscita della funzione.


Per -ftrapv, dai un'occhiata qui stackoverflow.com/questions/20851061/… .. sembra che ci sia un bug da molto tempo in attesa di essere risolto.
Arjun Sreedharan,

Potete controllare il commento sopra?
Suraj Jain,

-ftrapv è stato sostanzialmente sostituito da -fsanitize = signed-integer-overflow.
Marc Glisse,

139

Ecco i miei:

  • -Wextra, -Wall: essenziale.
  • -Wfloat-equal: utile perché di solito testare i numeri in virgola mobile per l'uguaglianza è male.
  • -Wundef: avvisa se un identificatore non inizializzato viene valutato in una #ifdirettiva.
  • -Wshadow: avvisa ogni volta che una variabile locale ombreggia un'altra variabile locale, un parametro o una variabile globale o ogni volta che una funzione incorporata viene ombreggiata.
  • -Wpointer-arith: avvisa se qualcosa dipende dalla dimensione di una funzione o di void.
  • -Wcast-align: avvisa ogni volta che viene lanciato un puntatore in modo tale da aumentare l'allineamento richiesto del bersaglio. Ad esempio, avvisa se a char *viene int *eseguito il cast su un computer su cui è possibile accedere a numeri interi solo a due o quattro byte.
  • -Wstrict-prototypes: avvisa se una funzione viene dichiarata o definita senza specificare i tipi di argomento.
  • -Wstrict-overflow=5: avvisa dei casi in cui il compilatore si ottimizza in base al presupposto che non si verifichi un overflow firmato. (Il valore 5 potrebbe essere troppo rigoroso, consultare la pagina del manuale.)
  • -Wwrite-strings: assegna alle costanti stringa la const char[lunghezza del tipo in ]modo che la copia dell'indirizzo di una in un non const char *puntatore riceva un avviso.
  • -Waggregate-return: avvisa se vengono definite o chiamate funzioni che restituiscono strutture o unioni.
  • -Wcast-qual: avvisa ogni volta che viene lanciato un puntatore per rimuovere un qualificatore di tipo dal tipo di destinazione * .
  • -Wswitch-default: avvisa ogni volta che switchun'istruzione non ha un defaultcaso * .
  • -Wswitch-enum: avvisa ogni volta che switchun'istruzione ha un indice di tipo enumerato e manca a caseper uno o più dei codici nominati di quell'enumerazione * .
  • -Wconversion: avvisa per conversioni implicite che potrebbero alterare un valore * .
  • -Wunreachable-code: avvisa se il compilatore rileva che il codice non verrà mai eseguito * .

Quelli contrassegnati * a volte danno troppi avvisi spuri, quindi li uso secondo necessità.


11
Elenco abbastanza completo, voglio solo aggiungerne un altro; -Wformat=2: Controlli di formato extra sulle funzioni printf / scanf.
schot

1
non sono impliciti tutti questi -Wall?
chacham15,

2
@ chacham15, no, non la penso così. gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
Alok Singhal

1
@Alok hmm, forse non è standard tra le distribuzioni? So che sul mio mbp devo spegnere esplicitamente -Wwrite-stringsperché lo odio così tanto.
chacham15,

@ chacham15, forse. Ma la descrizione per -Wwrite-stringsspecificamente dice che non fa parte di -Wall: gcc.gnu.org/onlinedocs/gcc/… . Forse qualcos'altro nella tua configurazione sta impostando quella bandiera? O forse stai compilando C ++?
Alok Singhal,

52

Utilizzare sempre -Oo superiore ( -O1, -O2, -Os, ecc). Al livello di ottimizzazione predefinito, gcc punta alla velocità di compilazione e non fa abbastanza analisi per mettere in guardia su cose come variabili unitizzate.

Prendi in considerazione l'idea di creare una -Werrorpolitica, poiché gli avvisi che non fermano la compilazione tendono a essere ignorati.

-Wall praticamente attiva gli avvisi che sono molto probabili essere errori.

Gli avvisi inclusi in -Wextratendono a contrassegnare il codice comune e legittimo. Possono essere utili per le revisioni del codice (anche se i programmi stile lanugine trovano molte più insidie ​​più flessibili), ma non li accenderei per il normale sviluppo.

-Wfloat-equal è una buona idea se gli sviluppatori del progetto non hanno familiarità con il virgola mobile e una cattiva idea se lo sono.

-Winit-selfè utile; Mi chiedo perché non sia incluso in -Wuninitialized.

-Wpointer-arithè utile se si dispone di codice per lo più portatile con cui non funziona -pedantic.


9
+1 per "-Wfloat-equal è una buona idea se gli sviluppatori del progetto non hanno familiarità con il virgola mobile e una cattiva idea se lo sono." soprattutto la seconda metà. :-)
R .. GitHub FERMA AIUTANDO ICE

39
-save-temps

Questo lascia dietro i risultati del preprocessore e dell'assemblaggio.

La fonte preelaborata è utile per il debug delle macro.

L'assemblaggio è utile per determinare quali ottimizzazioni sono entrate in vigore. Ad esempio, potresti voler verificare che GCC stia eseguendo l'ottimizzazione delle chiamate di coda su alcune funzioni ricorsive, poiché senza di essa puoi potenzialmente traboccare lo stack.


Mi chiedevo come fossi riuscito a farlo ... Ho sempre chiesto a gcc di scaricare l'assemblaggio se ne avevo bisogno.

35

Sono sorpreso che nessuno l'abbia ancora detto: la bandiera più utile per quanto mi riguarda è quella -gche mette le informazioni di debug nell'eseguibile in modo che tu possa eseguirne il debug e scorrere la fonte (a meno che tu non sia competente e leggendo assembly e come il stepicomando) di un programma mentre è in esecuzione.


35

-fmudflap - aggiunge i controlli di runtime a tutte le operazioni di puntatore rischioso per catturare UB. Questo immunizza efficacemente il buffer del programma di nuovo overflow e aiuta a catturare tutti i tipi di puntatori penzolanti.

Ecco una demo:

$ cat mf.c 
int main()
{
 int a[10];
 a[10]=1; // <-- o noes, line 4
}

$ gcc -fmudflap mf.c -lmudflap
$ ./a.out 
*******
mudflap violation 1 (check/write): time=1280862302.170759 ptr=0x7fff96eb3d00 size=44
pc=0x7f3a575503c1 location=`mf.c:4:2 (main)'
      /usr/lib/libmudflap.so.0(__mf_check+0x41) [0x7f3a575503c1]
      ./a.out(main+0x90) [0x400a54]
      /lib/libc.so.6(__libc_start_main+0xfd) [0x7f3a571e2c4d]
Nearby object 1: checked region begins 0B into and ends 4B after
mudflap object 0xf9c560: name=`mf.c:3:6 (main) a'
bounds=[0x7fff96eb3d00,0x7fff96eb3d27] size=40 area=stack check=0r/3w liveness=3
alloc time=1280862302.170749 pc=0x7f3a57550cb1
number of nearby objects: 1

Hmmm, il mudflap sembra piuttosto brutto: P
Matt Joiner,

9
-fmudflapnon è più supportato da GCC 4.9, si ottiene warning: switch '-fmudflap' is no longer supported. È stato sostituito da AddressSanitizer.
Agostino,

21

Non proprio correlato a C / C ++, ma utile comunque:

@file

Metti tutti i flag di cui sopra (che tutti hai specificato) in un 'file', e usa questo flag sopra per usare tutti i flag in quel file.

per esempio:

File: compilerFlags

-Parete

-STD = c99

-Wextra

Quindi compilare:

gcc yourSourceFile @compilerFlags

15

-march=native per produrre codice ottimizzato per la piattaforma (= chip) su cui si sta compilando


2
Se stai compilando per macchine non native dove non conosci il target, puoi usare mtune = xxx che ottimizza senza usare set di istruzioni. Ad esempio mtune = generico è tenuto aggiornato con i processori "medi".
Turix,

15

Se è necessario conoscere i flag del preprocessore predefiniti dal compilatore:

echo | gcc -E -dM -

13

Non è davvero utile per rilevare errori, ma l' -masm=intelopzione menzionata raramente rende l'utilizzo -Sper ispezionare l'output dell'assemblaggio molto, molto più bello.

La sintassi dell'assemblaggio AT&T mi fa troppo male alla testa.


2
La differenza tra AT&T e Intel per me è la differenza tra C # e Java. Solo sintassi. Entrambi orribili. :)
Matt Joiner il

2
+1 @michael per fare in modo che gcc usi la sintassi di Intel invece del dio terribile at & t. L'ispezione dell'assemblaggio utilizza un numero sufficiente di cicli cerebrali: non è necessario sprecare cicli cerebrali che src precede in codici operativi. Ora se solo gcc supporta __asm ​​{} come altri compilatori, siamo pronti!
greatwolf,

10

Il mio makefile generalmente contiene

  CFLAGS= -Wall -Wextra -Weffc++ -Os -ggdb
  ...
  g++ $(CFLAGS) -o junk $<
  gcc $(CFLAGS) -o $@ $<
  rm -f junk

La più importante di queste opzioni è stata discussa in precedenza, quindi sottolineerò le due caratteristiche che non sono ancora state evidenziate:

Anche se sto lavorando su una base di codice che necessità di essere semplice C per la portabilità in una certa piattaforma che ancora non ha alcun compilatore C ++ decente, faccio un compilazione "extra" con il compilatore C ++ (in aggiunta al compilatore C). Che ha 3 vantaggi:

  1. il compilatore C ++ mi dà occasionalmente messaggi di avviso migliori rispetto al compilatore C.
  2. Il compilatore C ++ accetta l'opzione -Weffc ++, che di tanto in tanto mi dà alcuni consigli utili, che mi perderei se lo compilassi solo in semplice C.
  3. Posso mantenere il codice relativamente facile da trasferire su C ++, evitando alcune condizioni al contorno in cui il semplice codice C non è un codice C ++ (come la definizione di una variabile chiamata "bool").

Sì, sono una Pollyanna irrimediabilmente ottimista che continua a pensare che sicuramente ogni mese ormai una piattaforma verrà dichiarata obsoleta o otterrà un compilatore C ++ decente e finalmente potremo passare al C ++. Nella mia mente, è inevitabile - l'unica domanda è se ciò accade prima o dopo che il management alla fine emetta un pony per tutti. :-)


Un buon punto per scriverlo come C ++, lo considero spesso. (sottoinsieme naturalmente)
Matt Joiner

6
Vorrei sottolineare che C non sarà mai deprecato a favore del C ++, scusa :)
Matt Joiner

4
considera -o / dev / null invece di rm -f junk
ulidtko

9
-Wstrict-prototypes -Wmissing-prototypes

10
E -Wold-style-definitionse hai a che fare con recidivi che pensano che le funzioni di stile K&R siano una buona idea, anche con dichiarazioni prototipate. (Ho a che fare con persone del genere. Mi dà davvero fastidio quando trovo un nuovo codice scritto in K&R. È abbastanza brutto avere roba legacy di K&R che non è stata risolta, ma nuovo codice! Grump !!!)
Jonathan Leffler

9

Ecco una grande bandiera che non è stata menzionata:

-Werror-implicit-function-declaration

Dare un errore ogni volta che viene utilizzata una funzione prima di essere dichiarata.


8
man gcc

Il manuale è pieno di bandiere interessanti con buone descrizioni. Tuttavia, -Wall probabilmente renderà gcc il più dettagliato possibile. Se desideri dati più interessanti, dovresti dare un'occhiata a valgrind o ad altri strumenti per verificare la presenza di errori.


1
È loooooooooooooooooooooooooooooooong, però. man gcc | nlriporta oltre 11000 righe. Questo è molto più della famigerata bashmanpage!
nuovo123456,

12
Grazie a dio l'hanno riempito in una pagina man, invece di una di quelle pagine "info" irripetibili.
Matt Joiner,

6

Bene, -Wextradovrebbe essere anche standard. -Werrortrasforma gli avvisi in errori (che possono essere molto fastidiosi, specialmente se si compila senza -Wno-unused-result). -pedanticin combinazione constd=c89 fornisce ulteriori avvisi se si utilizzano le funzionalità C99.

Ma questo è tutto. Non è possibile ottimizzare un compilatore C in qualcosa di più tipo-save rispetto a C stesso.


6

-M* famiglia di opzioni.

Ciò consente di scrivere file che determinano automaticamente da quali file di intestazione dovrebbero dipendere i file sorgente c o c ++. GCC genererà i file make con queste informazioni sulla dipendenza, quindi li includerai dal tuo file make principale.

Ecco un esempio di un makefile estremamente generico che utilizza -MD e -MP che compilerà una directory piena di file sorgente e di intestazione c ++ e scoprirà automaticamente tutte le dipendenze:

CPPFLAGS += -MD -MP                                         
SRC = $(wildcard *.cpp)                                                       

my_executable: $(SRC:%.cpp=%.o)                                                        
        g++ $(LDFLAGS) -o $@ $^                                               

-include $(SRC:%.cpp=%.d)

Ecco un post sul blog che ne discute in modo più approfondito: http://www.microhowto.info/howto/automatically_generate_makefile_dependencies.html


6

C'è -Werror, che tratta tutti gli avvisi come errori e ferma la compilazione. La gccpagina del manuale spiega tutte le opzioni della riga di comando per il compilatore.


@Matt Joiner: Dal momento che non hai menzionato l'architettura della macchina che stai utilizzando, le gccbandiere potrebbero essere diverse tra le tue e qualsiasi collegamento suggerito da chiunque. Questo è il motivo per cui le pagine di manuale sono fornite con il software.
Greg Hewgill il

4

-Wfloat-equal

Da: http://mces.blogspot.com/2005/07/char-const-argv.html

Uno degli altri nuovi avvertimenti che mi piace è il -Wfloat-equal. Quello avverte ogni volta che [si ha] un numero in virgola mobile in una condizione di uguaglianza. È geniale! Se hai programmato un computer grafica o (peggio :) un algoritmo di geometria computazionale, sai che non ci sono mai due float che corrispondono all'uguaglianza ...


10
I miei carri non coincidono con l'uguaglianza, come so quello che sto facendo.
Roland Illig,

4

Ho trovato questo thread alla ricerca di un flag per risolvere un problema specifico, non lo vedo qui, quindi ne aggiungerò uno che mi stava solo sconcertando sul mio post :

La -Wformat=2bandiera

-Wformat=> Controlla le chiamate a printfe scanf, ecc., Per assicurarsi che gli argomenti forniti abbiano tipi appropriati alla stringa di formato specificata ...

E la parte davvero importante al riguardo ( secondo il manuale GCC ):

-Wformatè incluso in -Wall. Per un maggiore controllo su alcuni aspetti del formato di controllo, le opzioni -Wformat-y2k, -Wno-format-extra-args, -Wno-format-zero-length, -Wformat-nonliteral, -Wformat-security, e -Wformat=2sono disponibili, ma non sono inclusi nel -Wall.`

Quindi, solo perché hai -Wallnon significa che hai tutto. ;)


3

A volte lo uso -sper un eseguibile molto più piccolo:

-s
    Remove all symbol table and relocation information from the executable.

Fonte: http://gcc.gnu.org/onlinedocs/gcc/Link-Options.html#Link-Options


6
dovresti semplicemente eseguire stripil tuo binario, in questo modo puoi avere un binario con informazioni di debug, rimuoverlo in seguito per la distribuzione.
Hasturkun,

Sì, stripfunziona anche ma -spuò essere più semplice e veloce, anche se non è così elaborato come correrestrip
Vasiliy Sharapov

3

Mentre questa risposta può essere leggermente fuori tema e la domanda è un mio degno +1 da allora

Sono particolarmente interessato a eventuali avvisi aggiuntivi e / o e alla trasformazione di avvisi in errori in alcuni casi per ridurre al minimo qualsiasi discrepanza accidentale di tipo.
c'è uno strumento che dovrebbe rilevare TUTTI gli errori e i potenziali errori che potrebbero non essere ovvi, c'è uno splint che IMHO fa un lavoro migliore nel rilevare errori rispetto a gcc o qualsiasi altro compilatore. Questo è uno strumento degno di avere nel tuo forziere.

Il controllo statico tramite uno strumento di tipo lanugine come un splint, avrebbe dovuto far parte di una toolchain del compilatore.


Mostra sempre un errore impossibile archiviare il file del preprocessore in C: \ include, non sono sicuro di cosa fare
Suraj Jain,

2

Sono particolarmente interessato a eventuali avvisi aggiuntivi,

Inoltre -Wall, l' opzione -Wo -Wextra( -Wfunziona con le versioni precedenti di gcc e con quelle più recenti; le versioni più recenti supportano il nome alternativo -Wextra, che significa la stessa cosa, ma è più descrittivo) abilita vari avvisi aggiuntivi.

Ci sono anche ancora più avvertimenti che non sono abilitati da nessuno di questi, generalmente per cose che sono più discutibilmente cattive. Il set di opzioni disponibili dipende dalla versione di gcc che stai utilizzando - consulta man gcco info gccper i dettagli, oppure consulta la documentazione online per la particolare versione di gcc che ti interessa. Ed -pedanticemette tutti gli avvisi richiesti dal particolare standard in uso (che dipende su altre opzioni come -std=xxxo -ansi) e si lamenta dell'uso delle estensioni gcc.

e / o e trasformare gli avvisi in errori in alcuni casi per minimizzare assolutamente eventuali disallineamenti accidentali di tipo.

-Werrortrasforma tutti gli avvisi in errori. Tuttavia, non credo che gcc ti permetta di farlo in modo selettivo per avvisi particolari.

Probabilmente scoprirai che devi essere selettivo su quali avvisi sono abilitati in base al progetto (specialmente se lo usi -Werror), poiché i file di intestazione di librerie esterne possono far scattare alcuni di essi. ( -pedanticin particolare tende a non essere utile in questo senso, nella mia esperienza.)


4
"Non credo che gcc ti permetta di farlo in modo selettivo per avvisi particolari, però." In realtà, puoi farlo -Werror=some-warning.
Matthew Flaschen,

0
  • -Wmissing-prototypes: Se viene definita una funzione globale senza una precedente dichiarazione del prototipo.
  • -Wformat-security: Avverte dell'utilizzo di funzioni di formato che rappresentano possibili problemi di sicurezza. Al momento, questo avverte di chiamate printfe scanffunzioni in cui la stringa di formato non è una stringa letterale e non ci sono argomenti di formato

0
  • -Werror=return-type: Impone errore quando la funzione non ha ritorno in gcc. È /we4716in Visual Studio.

  • -Werror=implicit-function-declaration: Impone errore quando la funzione viene utilizzata senza definita / non inclusa. È /we4013in Visual Studio.

  • -Werror=incompatible-pointer-types: Prima dell'errore quando il tipo di puntatore non corrisponde al tipo di puntatore previsto. È /we4133in Visual Studio.

In realtà, mi piacerebbe mantenere il mio codice C multipiattaforma e utilizzo CMake e inserisco i cflags forniti in CMakeLists.txt come:

if (CMAKE_SYSTEM_NAME MATCHES "Windows")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /we4013 /we4133 /we4716")
elseif (CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_SYSTEM_NAME MATCHES "Darwin")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror=implicit-function-declaration -Werror=incompatible-pointer-types -Werror=return-type")
endif()
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.