Nützliche GCC-Flags für C.


157

Welche anderen wirklich nützlichen, aber weniger bekannten Compiler-Flags gibt es neben dem Setzen -Wallund Setzen -std=XXXfür die Verwendung in C?

Ich bin besonders an zusätzlichen Warnungen interessiert und / oder daran, Warnungen in einigen Fällen in Fehler umzuwandeln, um versehentliche Typinkongruenzen absolut zu minimieren.


9
Nun -save-temps, -Wshadowund -fmudflapwaren die größten Funde, von denen ich dank allem nichts wusste.
Matt Joiner

Kontext, soweit ich das beurteilen kann: Ausführen gcc -c [flags-go-here] -o myprog.o myprog.c, um ein C-Programm zu kompilieren (nicht zu verknüpfen).
Rory O'Kane

Antworten:


64

Einige der -fOptionen zur Codegenerierung sind interessant:

  • Die -ftrapvFunktion bewirkt, dass das Programm bei einem vorzeichenbehafteten Ganzzahlüberlauf abgebrochen wird (formal "undefiniertes Verhalten" in C).

  • -fverbose-asmist nützlich, wenn Sie mit kompilieren -S, um die Assembly-Ausgabe zu untersuchen - es werden einige informative Kommentare hinzugefügt.

  • -finstrument-functions Fügt Code hinzu, um vom Benutzer bereitgestellte Profilierungsfunktionen an jedem Funktionsein- und -ausgangspunkt aufzurufen.


Für -ftrapv, tun Sie einen Blick hier haben stackoverflow.com/questions/20851061/... .. scheint , wie es lange einen Fehler wartet behoben.
Arjun Sreedharan

Können Sie den obigen Kommentar überprüfen?
Suraj Jain

-ftrapv wurde im Wesentlichen durch -fsanitize = signierter Ganzzahlüberlauf ersetzt.
Marc Glisse

139

Hier sind meine:

  • -Wextra, -Wall: wesentlich.
  • -Wfloat-equal: nützlich, da das Testen von Gleitkommazahlen auf Gleichheit normalerweise schlecht ist.
  • -Wundef: warnen, wenn eine nicht initialisierte Kennung in einer #ifDirektive ausgewertet wird .
  • -Wshadow: warnen, wann immer eine lokale Variable eine andere lokale Variable, einen Parameter oder eine globale Variable beschattet oder wann immer eine integrierte Funktion beschattet wird.
  • -Wpointer-arith: warnen, wenn etwas von der Größe einer Funktion oder von abhängt void.
  • -Wcast-align: warnen, wenn ein Zeiger so geworfen wird, dass die erforderliche Ausrichtung des Ziels erhöht wird. Zum Beispiel warnen , wenn ein char *auf ein gegossen wird int *auf Maschinen , bei denen ganzen Zahlen können nur auf zwei oder vier Byte - Grenzen zugegriffen werden.
  • -Wstrict-prototypes: warn, wenn eine Funktion ohne Angabe der Argumenttypen deklariert oder definiert wird.
  • -Wstrict-overflow=5: warnt vor Fällen, in denen der Compiler unter der Annahme optimiert, dass kein signierter Überlauf auftritt. (Der Wert 5 ist möglicherweise zu streng, siehe Handbuchseite.)
  • -Wwrite-strings: Geben Sie Zeichenfolgenkonstanten die const char[Typlänge an,] damit beim Kopieren der Adresse von eins in einen Nichtzeiger const char *eine Warnung angezeigt wird.
  • -Waggregate-return: warnen, wenn Funktionen definiert oder aufgerufen werden, die Strukturen oder Gewerkschaften zurückgeben.
  • -Wcast-qual: warnen, wann immer ein Zeiger gesetzt wird, um ein Typqualifikationsmerkmal aus dem Zieltyp * zu entfernen .
  • -Wswitch-default: warnen, wenn eine switchAnweisung keinen defaultFall hat * .
  • -Wswitch-enum: warnen, wenn eine switchAnweisung einen Index vom Typ Aufzählung hat und casefür einen oder mehrere der genannten Codes dieser Aufzählung * kein Index vorhanden ist .
  • -Wconversion: warnt vor impliziten Konvertierungen, die einen Wert ändern können * .
  • -Wunreachable-code: warnen, wenn der Compiler feststellt, dass Code niemals ausgeführt wird * .

Die mit * gekennzeichneten geben manchmal zu viele falsche Warnungen aus, daher verwende ich sie nach Bedarf.


11
Ziemlich vollständige Liste, möchte nur noch eine hinzufügen; -Wformat=2: Zusätzliche Formatprüfungen für printf / scanf-Funktionen.
Schot

1
Sind all dies nicht impliziert durch -Wall?
Chacham15

2
@ Chacham15, nein, das glaube ich nicht. gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
Alok Singhal

1
@Alok hmm, vielleicht ist es nicht Standard unter Distributionen? Ich weiß, dass ich auf meinem MBP explizit ausschalten muss, -Wwrite-stringsweil ich es so sehr hasse.
Chacham15

@ Chacham15, vielleicht. Die Beschreibung für -Wwrite-stringsbesagt jedoch ausdrücklich, dass es nicht Teil von -Wall: gcc.gnu.org/onlinedocs/gcc/… ist . Vielleicht setzt etwas anderes in Ihrem Setup dieses Flag? Oder kompilieren Sie vielleicht C ++?
Alok Singhal

52

Verwenden Sie immer -Ooder über ( -O1, -O2, -Os, etc.). Auf der Standardoptimierungsstufe setzt gcc auf Kompilierungsgeschwindigkeit und führt nicht genügend Analysen durch, um vor Dingen wie einheitlichen Variablen zu warnen.

Erwägen Sie, -WerrorRichtlinien zu erstellen, da Warnungen, die die Kompilierung nicht stoppen, häufig ignoriert werden.

-Wall Aktiviert so ziemlich die Warnungen, bei denen es sich sehr wahrscheinlich um Fehler handelt.

In enthaltene Warnungen kennzeichnen in der -WextraRegel allgemeinen, legitimen Code. Sie können für Codeüberprüfungen nützlich sein (obwohl Programme im Fusselstil viel mehr Fallstricke flexibler finden), aber ich würde sie für die normale Entwicklung nicht aktivieren.

-Wfloat-equal ist eine gute Idee, wenn die Entwickler des Projekts mit Gleitkommazahlen nicht vertraut sind, und eine schlechte Idee, wenn sie es sind.

-Winit-selfist nützlich; Ich frage mich, warum es nicht in enthalten ist -Wuninitialized.

-Wpointer-arithist nützlich, wenn Sie meistens portablen Code haben, der nicht funktioniert -pedantic.


9
+1 für "-Wfloat-gleich ist eine gute Idee, wenn die Entwickler des Projekts mit Gleitkomma nicht vertraut sind, und eine schlechte Idee, wenn sie es sind." vor allem die zweite Hälfte davon. :-)
R .. GitHub STOP HELPING ICE

39
-save-temps

Dies hinterlässt die Ergebnisse des Präprozessors und der Baugruppe.

Die vorverarbeitete Quelle ist nützlich zum Debuggen von Makros.

Die Assembly ist nützlich, um festzustellen, welche Optimierungen wirksam wurden. Beispielsweise möchten Sie möglicherweise überprüfen, ob GCC bei einigen rekursiven Funktionen eine Tail-Call-Optimierung durchführt, da Sie ohne diese Funktion möglicherweise den Stapel überlaufen können.


Ich habe mich gefragt, wie Sie das dazu gebracht haben ... Ich habe gcc immer nur gebeten, die Baugruppe zu entleeren, wenn ich sie brauchte.

35

Ich bin überrascht, dass dies noch niemand gesagt hat - das für mich nützlichste Flag ist, -gdass Debugging-Informationen in die ausführbare Datei eingefügt werden, sodass Sie sie debuggen und durch die Quelle gehen können (es sei denn, Sie beherrschen und lesen Assembly und wie der stepiBefehl) eines Programms, während es ausgeführt wird.


35

-fmudflap - Fügt allen riskanten Zeigeroperationen Laufzeitprüfungen hinzu, um UB abzufangen . Dies immunisiert Ihr Programm effektiv gegen Pufferüberläufe und hilft, alle Arten von baumelnden Zeigern zu fangen.

Hier ist eine 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, Schmutzfänger scheint ziemlich böse: P
Matt Joiner

9
-fmudflapwird seit GCC 4.9 nicht mehr unterstützt warning: switch '-fmudflap' is no longer supported. Es wurde von AddressSanitizer ersetzt.
Agostino

21

Nicht wirklich mit C / C ++ verwandt, aber trotzdem nützlich:

@file

Fügen Sie alle oben genannten guten Flags (die Sie alle angegeben haben) in eine 'Datei' ein und verwenden Sie dieses obige Flag, um alle Flags in dieser Datei zusammen zu verwenden.

z.B:

Datei: compilerFlags

-Mauer

-std = c99

-Wextra

Dann kompilieren Sie:

gcc yourSourceFile @compilerFlags

15

-march=native um optimierten Code für die Plattform (= Chip) zu erstellen, auf der Sie kompilieren


2
Wenn Sie für nicht native Computer kompilieren, auf denen Sie das Ziel nicht kennen, können Sie mtune = xxx verwenden, das ohne Verwendung von Befehlssätzen optimiert wird. Zum Beispiel wird mtune = generic mit den "durchschnittlichen" Fallprozessoren auf dem neuesten Stand gehalten.
Turix

15

Wenn Sie die vom Compiler vordefinierten Präprozessor-Flags kennen müssen:

echo | gcc -E -dM -

13

Es ist nicht wirklich hilfreich, um Fehler zu erkennen, aber die selten erwähnte -masm=intelOption macht die -SÜberprüfung der Baugruppenausgabe viel, viel schöner.

Die Syntax der AT & T-Assembly schmerzt meinen Kopf viel zu sehr.


2
Der Unterschied zwischen AT & T und Intel ist für mich der Unterschied zwischen C # und Java. Nur Syntax. Beides schrecklich. :)
Matt Joiner

2
+1 @michael, damit gcc die Intel-Syntax anstelle des schrecklichen Gottes bei & t verwendet. Bei der Inspektion der Baugruppe werden genügend Gehirnzyklen verwendet - es ist nicht erforderlich, Gehirnzyklen zu verschwenden, die src vor dem Dest in Opcodes abläuft. Wenn nur gcc wie andere Compiler das Inline __asm ​​{} unterstützt, sind wir fertig!
Urwolf

10

Mein Makefile enthält normalerweise

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

Die wichtigsten dieser Optionen wurden bereits erörtert, daher möchte ich auf die beiden Funktionen hinweisen, auf die noch nicht hingewiesen wurde:

Auch wenn ich auf einer Code - Basis gerade arbeite , dass Bedürfnisse Ebene C für die Portabilität zu einem gewissen Plattform sein , die noch keine anständigen C ++ Compiler hat, muß ich eine „extra“ Kompilierung mit dem C ++ Compiler (zusätzlich zu dem C - Compiler). Das hat 3 Vorteile:

  1. Der C ++ - Compiler gibt mir gelegentlich bessere Warnmeldungen als der C-Compiler.
  2. Der C ++ - Compiler akzeptiert die Option -Weffc ++, die mir gelegentlich einige nützliche Tipps gibt, die ich verpassen würde, wenn ich sie nur in einfachem C kompilieren würde.
  3. Ich kann den Code relativ einfach auf C ++ portieren, wobei einige Randbedingungen vermieden werden, bei denen einfacher C-Code ungültiger C ++ - Code ist (z. B. das Definieren einer Variablen mit dem Namen "bool").

Ja, ich bin eine hoffnungslos optimistische Pollyanna, die sicher jeden Monat daran denkt, dass eine Plattform entweder für veraltet erklärt wird oder einen anständigen C ++ - Compiler erhält, und wir können endlich zu C ++ wechseln. In meinen Augen ist das unvermeidlich - die einzige Frage ist, ob dies vor oder nach dem Management geschieht, das schließlich jedem ein Pony ausstellt. :-)


Ein guter Punkt beim Schreiben als C ++, ich denke oft darüber nach. (Teilmenge natürlich)
Matt Joiner

6
Ich sollte darauf hinweisen, dass C, das zugunsten von C ++ veraltet ist, niemals passieren wird, sorry :)
Matt Joiner

4
Betrachten Sie -o / dev / null anstelle von rm -f Junk
ulidtko

9
-Wstrict-prototypes -Wmissing-prototypes

10
Und -Wold-style-definitionwenn Sie mit Rückfälligen zu tun haben, die Funktionen im K & R-Stil für eine gute Idee halten, selbst bei prototypisierten Deklarationen. (Ich muss mit solchen Leuten umgehen. Es ärgert mich wirklich, wenn ich neuen Code in K & R finde. Es ist schon schlimm genug, K & R-Legacy-Sachen zu haben, die nicht repariert sind, aber neuen Code! Grump !!!)
Jonathan Leffler

9

Hier ist eine großartige Flagge, die nicht erwähnt wurde:

-Werror-implicit-function-declaration

Geben Sie einen Fehler aus, wenn eine Funktion verwendet wird, bevor Sie deklariert werden.


8
man gcc

Das Handbuch ist voller interessanter Flaggen mit guten Beschreibungen. -Wall wird gcc jedoch wahrscheinlich so ausführlich wie möglich machen. Wenn Sie interessantere Daten wünschen, sollten Sie sich valgrind oder ein anderes Tool ansehen, um nach Fehlern zu suchen.


1
Es ist jedoch loooooooooooooooooooooooooooooooong. man gcc | nlmeldet über 11000 Zeilen. Das ist mehr als die berüchtigte bashManpage!
new123456

12
Gott sei Dank haben sie es in eine Manpage gepackt, anstatt in eine dieser gottesfürchtigen, nicht befahrbaren "Info" -Seiten.
Matt Joiner

6

Nun, -Wextrasollte auch Standard sein. -Werrorverwandelt Warnungen in Fehler (was sehr ärgerlich sein kann, insbesondere wenn Sie ohne kompilieren -Wno-unused-result). -pedanticIn Kombination mit erhalten std=c89Sie zusätzliche Warnungen, wenn Sie C99-Funktionen verwenden.

Aber das war es schon. Sie können einen C-Compiler nicht auf etwas typsparenderes als C selbst einstellen.


6

-M* Familie von Optionen.

Mit diesen können Sie make-Dateien schreiben, die automatisch herausfinden, von welchen Header-Dateien Ihre c- oder c ++ - Quelldateien abhängen sollten. GCC generiert Make-Dateien mit diesen Abhängigkeitsinformationen, und Sie schließen sie dann aus Ihrer primären Make-Datei ein.

Hier ist ein Beispiel für ein extrem generisches Makefile mit -MD und -MP, das ein Verzeichnis voller C ++ - Quell- und Header-Dateien kompiliert und alle Abhängigkeiten automatisch ermittelt:

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

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

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

Hier ist ein Blog-Beitrag, der es ausführlicher behandelt: http://www.microhowto.info/howto/automatically_generate_makefile_dependencies.html


6

Es gibt -Werror, das alle Warnungen als Fehler behandelt und die Kompilierung stoppt. Auf der gccHandbuchseite werden alle Befehlszeilenoptionen für Ihren Compiler erläutert.


@Matt Joiner: Da Sie nicht erwähnt haben, welche Maschinenarchitektur Sie verwenden, können die gccFlags zwischen Ihren und den von irgendjemandem vorgeschlagenen Links unterschiedlich sein. Aus diesem Grund werden Handbuchseiten mit Ihrer Software geliefert.
Greg Hewgill

4

-Wfloat-equal

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

Eine der anderen neuen Warnungen, die ich mag, ist das -Wfloat-Equal. Dieser warnt immer dann, wenn Sie eine Gleitkommazahl in einer Gleichheitsbedingung haben. Das ist brillant! Wenn Sie jeweils eine Computergrafik oder einen (schlimmer noch :) rechnergestützten Geometriealgorithmus programmiert haben, wissen Sie, dass keine zwei Floats jemals mit Gleichheit übereinstimmen ...


10
Meine Wagen stimmen mit der Gleichheit überein, da ich weiß, was ich tue.
Roland Illig

4

Ich habe festgestellt, dass dieser Thread nach einer Flagge sucht, um ein bestimmtes Problem zu beheben. Ich sehe sie hier nicht, daher füge ich eine hinzu, die mich in meinem Beitrag nur verblüfft hat :

Die -Wformat=2Flagge

-Wformat=> Überprüfen Sie die Aufrufe von printfund scanfusw., um sicherzustellen, dass die angegebenen Argumente Typen haben, die der angegebenen Formatzeichenfolge entsprechen ...

Und das wirklich Wichtige daran ( laut GCC-Handbuch ):

-Wformatist enthalten in -Wall. Für mehr Kontrolle über einige Aspekte der Formatprüfung, die Optionen -Wformat-y2k, -Wno-format-extra-args, -Wno-format-zero-length, -Wformat-nonliteral, -Wformat-security, und -Wformat=2stehen zur Verfügung, sind aber nicht in -Wall.` enthalten

Nur weil Sie haben, -Wallheißt das nicht, dass Sie alles haben. ;)


3

Ich benutze manchmal -sfür eine viel kleinere ausführbare Datei:

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

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


6
Sie sollten nur stripIhre Binärdatei ausführen. Auf diese Weise können Sie eine Binärdatei mit Debug-Informationen erstellen und später zur Verteilung entfernen.
Hasturkun

Ja, stripfunktioniert auch, -skann aber schneller und einfacher sein, obwohl es nicht so aufwändig ist wie das Laufenstrip
Vasiliy Sharapov

3

Diese Antwort mag zwar etwas vom Thema abweichen und die Frage ist eine +1 von mir wert, da

Ich bin besonders an zusätzlichen Warnungen interessiert und / oder daran, Warnungen in einigen Fällen in Fehler umzuwandeln, um versehentliche Typinkongruenzen absolut zu minimieren.
Es gibt ein Tool, das ALLE Fehler und potenziellen Fehler aufspüren sollte, die möglicherweise nicht offensichtlich sind. Es gibt eine Schiene, mit der IMHO Fehler besser erkennen kann als mit gcc oder einem anderen Compiler. Das ist ein würdiges Werkzeug, das Sie in Ihrer Werkzeugkiste haben sollten.

Die statische Überprüfung über ein fusselfreies Werkzeug wie eine Schiene sollte Teil einer Compiler-Toolchain sein.


Es zeigt immer, dass ein Fehler keine Präprozessor-Datei in C: \ include ablegen kann. Ich bin nicht sicher, was ich tun soll
Suraj Jain

2

Ich bin besonders an zusätzlichen Warnungen interessiert,

Darüber hinaus ermöglicht -Walldie Option -Woder -Wextra( -Wfunktioniert sowohl mit älteren als auch mit neueren Versionen von gcc; neuere Versionen unterstützen den alternativen Namen -Wextra, was dasselbe bedeutet, aber aussagekräftiger ist) verschiedene zusätzliche Warnungen.

Es gibt auch noch mehr Warnungen, die von keiner dieser Warnungen aktiviert werden, im Allgemeinen für Dinge, die fragwürdiger sind. Die Menge der verfügbaren Optionen ist abhängig davon , welche gcc Version Sie verwenden - konsultieren man gccoder info gccfür weitere Details oder die siehe Online - Dokumentation . Für die jeweilige gcc Version Sie interessiert sind und -pedanticProbleme alle durch die jeweilige Norm bedarf Warnungen verwendet (das hängt auf andere Optionen wie -std=xxxoder -ansi) und beschwert sich über die Verwendung von gcc-Erweiterungen.

und / oder und in einigen Fällen Warnungen in Fehler umzuwandeln, um versehentliche Fehlanpassungen vom Typ absolut zu minimieren.

-Werrorverwandelt alle Warnungen in Fehler. Ich glaube nicht, dass Sie mit gcc dies selektiv für bestimmte Warnungen tun können.

Sie werden wahrscheinlich feststellen, dass Sie selektiv auswählen müssen, welche Warnungen pro Projekt aktiviert werden (insbesondere wenn Sie sie verwenden -Werror), da Header-Dateien aus externen Bibliotheken einige davon auslösen können. ( -pedanticInsbesondere ist dies meiner Erfahrung nach in dieser Hinsicht eher wenig hilfreich.)


4
"Ich glaube nicht, dass Sie mit gcc das selektiv für bestimmte Warnungen tun können." Eigentlich kannst du mit -Werror=some-warning.
Matthew Flaschen

0
  • -Wmissing-prototypes: Wenn eine globale Funktion ohne vorherige Prototypdeklaration definiert ist.
  • -Wformat-security: Warnt vor der Verwendung von Formatfunktionen, die mögliche Sicherheitsprobleme darstellen. Derzeit warnt dies vor Aufrufen printfund scanfFunktionen, bei denen die Formatzeichenfolge kein Zeichenfolgenliteral ist und keine Formatargumente vorhanden sind

0
  • -Werror=return-type: Fehler erzwingen, wenn die Funktion in gcc keine Rückgabe hat. Es ist /we4716in Visual Studio.

  • -Werror=implicit-function-declaration: Fehler erzwingen, wenn die Funktion ohne definiert / nicht enthalten verwendet wird. Es ist /we4013in Visual Studio.

  • -Werror=incompatible-pointer-types: Vor dem Fehler, wenn der Typ eines Zeigers nicht mit dem erwarteten Zeigertyp übereinstimmt. Es ist /we4133in Visual Studio.

Eigentlich möchte ich meinen C-Code plattformübergreifend behalten, CMake verwenden und die bereitgestellten cflags wie folgt in CMakeLists.txt einfügen:

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()
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.