Drapeaux GCC utiles pour C


157

Au-delà des paramètres -Wallet des paramètres -std=XXX, quels sont les autres indicateurs de compilateur vraiment utiles, mais moins connus, qui peuvent être utilisés en C?

Je suis particulièrement intéressé par les avertissements supplémentaires et / ou par la transformation des avertissements en erreurs dans certains cas afin de minimiser absolument toute incompatibilité de type accidentelle.


9
Eh bien -save-temps, -Wshadowet -fmudflapc'était les plus belles découvertes que je ne connaissais pas, merci à tous.
Matt Joiner

Contexte, pour autant que je sache: courir gcc -c [flags-go-here] -o myprog.o myprog.cpour compiler (pas lier) un programme C.
Rory O'Kane

Réponses:


64

Plusieurs -foptions de génération de code sont intéressantes:

  • La -ftrapvfonction provoquera l'arrêt du programme en cas de dépassement d'entier signé (formellement «comportement indéfini» en C).

  • -fverbose-asmest utile si vous compilez avec -Spour examiner la sortie de l'assembly - il ajoute quelques commentaires informatifs.

  • -finstrument-functions ajoute du code pour appeler les fonctions de profilage fournies par l'utilisateur à chaque entrée de fonction et point de sortie.


Pour -ftrapv, jetez un œil ici stackoverflow.com/questions/20851061/… .. il semble qu'il y ait un bogue qui attend depuis longtemps d'être corrigé.
Arjun Sreedharan

Pouvez-vous vérifier le commentaire ci-dessus?
Suraj Jain

-ftrapv a été essentiellement remplacé par -fsanitize = signed-integer-overflow.
Marc Glisse

139

Voici les miens:

  • -Wextra, -Wall: indispensable.
  • -Wfloat-equal: utile car il est généralement mauvais de tester l'égalité des nombres à virgule flottante.
  • -Wundef: avertit si un identifiant non initialisé est évalué dans une #ifdirective.
  • -Wshadow: avertit chaque fois qu'une variable locale masque une autre variable locale, un paramètre ou une variable globale ou chaque fois qu'une fonction intégrée est masquée.
  • -Wpointer-arith: avertir si quelque chose dépend de la taille d'une fonction ou de void.
  • -Wcast-align: avertit chaque fois qu'un pointeur est lancé de telle sorte que l'alignement requis de la cible est augmenté. Par exemple, avertissez si a char *est converti en un int *sur des machines où les entiers ne sont accessibles qu'à des limites de deux ou quatre octets.
  • -Wstrict-prototypes: avertit si une fonction est déclarée ou définie sans spécifier les types d'arguments.
  • -Wstrict-overflow=5: avertit des cas où le compilateur optimise en partant de l'hypothèse que le débordement signé ne se produit pas. (La valeur 5 peut être trop stricte, voir la page de manuel.)
  • -Wwrite-strings: donnez aux constantes de chaîne la const char[longueur du type ]pour que la copie de l'adresse de l'une dans un non- const char *pointeur obtienne un avertissement.
  • -Waggregate-return: avertit si des fonctions qui renvoient des structures ou des unions sont définies ou appelées.
  • -Wcast-qual: avertit chaque fois qu'un pointeur est casté pour supprimer un qualificateur de type du type cible * .
  • -Wswitch-default: avertir chaque fois qu'une switchinstruction n'a pas de defaultcas * .
  • -Wswitch-enum: avertit chaque fois qu'une switchinstruction a un index de type énuméré et n'a pas de casepour un ou plusieurs des codes nommés de cette énumération * .
  • -Wconversion: avertit des conversions implicites qui peuvent modifier une valeur * .
  • -Wunreachable-code: avertit si le compilateur détecte que le code ne sera jamais exécuté * .

Ceux marqués * donnent parfois trop de faux avertissements, je les utilise donc au besoin.


11
Liste assez complète, je veux juste en ajouter une de plus; -Wformat=2: Vérifications de format supplémentaire sur les fonctions printf / scanf.
schot

1
ne sont-ils pas tous impliqués par -Wall?
chacham15

2
@ chacham15, non, je ne pense pas. gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
Alok Singhal

1
@Alok hmm, peut-être que ce n'est pas standard parmi les distributions? Je sais que sur mon mbp, je dois désactiver explicitement -Wwrite-stringsparce que je le déteste tellement.
chacham15

@ chacham15, peut-être. Mais la description -Wwrite-stringsprécise que cela ne fait pas partie de -Wall: gcc.gnu.org/onlinedocs/gcc/… . Peut-être que quelque chose d'autre dans votre configuration définit cet indicateur? Ou peut-être que vous compilez C ++?
Alok Singhal

52

Toujours utiliser -Oou au- dessus ( -O1, -O2, -Os, etc.). Au niveau d'optimisation par défaut, gcc opte pour la vitesse de compilation et ne fait pas assez d'analyse pour avertir de choses comme les variables unifiées.

Pensez à établir une -Werrorpolitique, car les avertissements qui n'arrêtent pas la compilation ont tendance à être ignorés.

-Wall active à peu près les avertissements qui sont très probablement des erreurs.

Les avertissements inclus dans -Wextraont tendance à signaler le code commun et légitime. Ils peuvent être utiles pour les révisions de code (bien que les programmes de style lint trouvent que beaucoup plus de pièges sont plus flexibles), mais je ne les activerais pas pour un développement normal.

-Wfloat-equal est une bonne idée si les développeurs du projet ne sont pas familiers avec la virgule flottante, et une mauvaise idée s'ils le sont.

-Winit-selfest utile; Je me demande pourquoi ce n'est pas inclus dans -Wuninitialized.

-Wpointer-arithest utile si vous avez du code principalement portable qui ne fonctionne pas avec -pedantic.


9
+1 pour "-Wfloat-equal est une bonne idée si les développeurs du projet ne connaissent pas la virgule flottante, et une mauvaise idée s'ils le sont." en particulier la seconde moitié. :-)
R .. GitHub STOP AIDER ICE

39
-save-temps

Cela laisse derrière les résultats du préprocesseur et de l'assemblage.

La source prétraitée est utile pour le débogage des macros.

L'assemblage est utile pour déterminer quelles optimisations sont entrées en vigueur. Par exemple, vous voudrez peut-être vérifier que GCC fait l'optimisation des appels de queue sur certaines fonctions récursives, car sans cela, vous pouvez potentiellement déborder la pile.


Je me suis demandé comment vous y parveniez ... J'ai toujours demandé à gcc de vider l'assembly si j'en avais besoin.

35

Je suis surpris que personne n'ait encore dit cela - l'indicateur le plus utile en ce qui me concerne est celui -gqui place les informations de débogage dans l'exécutable de sorte que vous puissiez le déboguer et parcourir la source (sauf si vous êtes compétent et lisez l'assembly et comme la stepicommande) d'un programme pendant son exécution.


35

-fmudflap - ajoute des vérifications d'exécution à toutes les opérations de pointeur à risque pour attraper UB. Cela immunise efficacement votre programme contre les débordements de tampon et aide à attraper toutes sortes de pointeurs pendantes.

Voici une démo:

$ 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, la bavette semble assez méchante: P
Matt Joiner

9
-fmudflapn'est plus pris en charge depuis GCC 4.9, vous obtenez warning: switch '-fmudflap' is no longer supported. Il a été remplacé par AddressSanitizer.
Agostino

21

Pas vraiment lié à C / C ++, mais utile quand même:

@file

Mettez tous les bons indicateurs ci-dessus (que vous avez tous spécifiés) dans un 'fichier' et utilisez cet indicateur ci-dessus pour utiliser tous les indicateurs de ce fichier ensemble.

par exemple:

Fichier: compilerFlags

-Mur

-std = c99

-Wextra

Puis compilez:

gcc yourSourceFile @compilerFlags

15

-march=native pour produire du code optimisé pour la plateforme (= puce) sur laquelle vous compilez


2
Si vous compilez pour des machines non natives dont vous ne connaissez pas la cible, vous pouvez utiliser mtune = xxx qui optimise sans utiliser de jeux d'instructions. Par exemple, mtune = generic est mis à jour avec les processeurs de cas "moyens".
Turix

15

Si vous avez besoin de connaître les indicateurs de préprocesseur qui sont prédéfinis par le compilateur:

echo | gcc -E -dM -

13

Ce n'est pas vraiment utile pour détecter les erreurs, mais l' -masm=inteloption rarement mentionnée rend l'utilisation -Sd'inspecter la sortie de l'assemblage beaucoup plus agréable.

La syntaxe d'assemblage AT&T me fait trop mal à la tête.


2
La différence entre AT&T et Intel pour moi est la différence entre C # et Java. Juste de la syntaxe. Les deux horribles. :)
Matt Joiner

2
+1 @michael pour avoir fait en sorte que gcc utilise la syntaxe intel au lieu du dieu terrible at & t. L'inspection de l'assemblage utilise suffisamment de cycles cérébraux - pas besoin de gaspiller les cycles cérébraux que src passe avant dest dans les opcodes. Maintenant, si seulement gcc prend en charge le __asm ​​{} inline comme les autres compilateurs, nous sommes tous prêts!
greatwolf

10

Mon makefile contient généralement

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

Les plus importantes de ces options ont déjà été discutées, je vais donc souligner les deux fonctionnalités qui n'ont pas encore été signalées:

Même si je travaille sur une base de code qui doit être en C pur pour la portabilité vers une plate-forme qui n'a toujours pas de compilateur C ++ décent, je fais une compilation "supplémentaire" avec le compilateur C ++ (en plus du compilateur C). Cela présente 3 avantages:

  1. le compilateur C ++ me donne parfois de meilleurs messages d'avertissement que le compilateur C.
  2. Le compilateur C ++ accepte l'option -Weffc ++, qui me donne parfois quelques conseils utiles, que je manquerais si je ne le compilais qu'en C.
  3. Je peux garder le code relativement facile à porter en C ++, en évitant quelques conditions aux limites où le code C brut est un code C ++ invalide (comme la définition d'une variable nommée "bool").

Oui, je suis un Pollyanna désespérément optimiste qui continue à penser que sûrement un mois maintenant que une plate - forme sera soit déclarée obsolète, ou gagner un compilateur C ++ décent, et nous pouvons enfin passer à C ++. Dans mon esprit, c'est inévitable - la seule question est de savoir si cela se produit avant ou après que la direction délivre enfin à tout le monde un poney. :-)


Un bon point avec l'écriture en C ++, je considère cela souvent. (sous-ensemble naturellement)
Matt Joiner

6
Je dois souligner que C étant obsolète au profit de C ++ ne se produira jamais, désolé :)
Matt Joiner

4
considérez -o / dev / null au lieu de rm -f junk
ulidtko

9
-Wstrict-prototypes -Wmissing-prototypes

10
Et -Wold-style-definitionsi vous avez affaire à des récidivistes qui pensent que les fonctions de style K&R sont une bonne idée, même avec des déclarations prototypées. (Je dois faire face à des gens comme ça. Cela m'énerve vraiment quand je trouve un nouveau code écrit en K&R. C'est déjà assez mauvais d'avoir des éléments K&R hérités qui ne sont pas corrigés, mais un nouveau code! Grump !!!)
Jonathan Leffler

9

Voici un excellent drapeau qui n'a pas été mentionné:

-Werror-implicit-function-declaration

Donne une erreur chaque fois qu'une fonction est utilisée avant d'être déclarée.


8
man gcc

Le manuel regorge d'indicateurs intéressants avec de bonnes descriptions. Cependant, -Wall rendra probablement gcc aussi verbeux que possible. Si vous voulez des données plus intéressantes, vous devriez jeter un oeil à valgrind ou à un autre outil pour vérifier les erreurs.


1
C'est loooooooooooooooooooooooooooooooong, cependant. man gcc | nlrapporte plus de 11 000 lignes. C'est plus que la fameuse bashpage de manuel!
nouveau123456

12
Dieu merci, ils l'ont entassée dans une page de manuel, au lieu d'une de ces pages "info" non navigables.
Matt Joiner

6

Eh bien, cela -Wextradevrait aussi être standard. -Werrortransforme les avertissements en erreurs (ce qui peut être très ennuyeux, surtout si vous compilez sans -Wno-unused-result). -pedanticen combinaison avec std=c89vous donne des avertissements supplémentaires si vous utilisez les fonctionnalités du C99.

Mais c'est à peu près tout. Vous ne pouvez pas régler un compilateur C en quelque chose de plus de sauvegarde de type que C lui-même.


6

-M* famille d'options.

Ceux-ci vous permettent d'écrire des fichiers de création qui déterminent automatiquement de quels fichiers d'en-tête vos fichiers source c ou c ++ devraient dépendre. GCC générera des fichiers make avec ces informations de dépendance, puis vous les incluerez à partir de votre fichier make principal.

Voici un exemple de makefile extrêmement générique utilisant -MD et -MP qui compilera un répertoire plein de fichiers source et d'en-tête C ++, et déterminera automatiquement toutes les dépendances:

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

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

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

Voici un article de blog qui en parle plus en profondeur: http://www.microhowto.info/howto/automatically_generate_makefile_dependencies.html


6

Il existe -Werror, qui traite tous les avertissements comme des erreurs et arrête la compilation. La gccpage de manuel explique chaque commutateur de ligne de commande pour votre compilateur.


@Matt Joiner: Puisque vous n'avez pas mentionné l'architecture de machine que vous utilisez, les gccindicateurs peuvent être différents entre le vôtre et le lien que quelqu'un pourrait suggérer. C'est pourquoi des pages de manuel sont fournies avec votre logiciel.
Greg Hewgill

4

-Wfloat-equal

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

L'un des autres nouveaux avertissements que j'aime est le -Wfloat-equal. Celui-ci avertit chaque fois que vous [avez] un nombre à virgule flottante dans une condition d'égalité. C'est génial! Si vous avez tous programmé un algorithme d'infographie ou (pire :) de géométrie de calcul, vous savez qu'aucun flotteur ne correspond jamais à l'égalité ...


10
Mes flotteurs ne correspondent à l' égalité, comme je sais ce que je fais.
Roland Illig

4

J'ai trouvé ce fil à la recherche d'un indicateur pour résoudre un problème spécifique, je ne le vois pas ici, je vais donc en ajouter un qui me stoppait juste sur mon message :

Le -Wformat=2drapeau

-Wformat=> Vérifiez les appels à printfet scanf, etc., pour vous assurer que les arguments fournis ont des types appropriés à la chaîne de format spécifiée ...

Et la partie vraiment importante à ce sujet ( selon le manuel GCC ):

-Wformatest inclus dans -Wall. Pour plus de contrôle sur certains aspects de la forme de contrôle, les options -Wformat-y2k, -Wno-format-extra-args, -Wno-format-zero-length, -Wformat-nonliteral, -Wformat-securityet -Wformat=2sont disponibles, mais ne sont pas inclus dans -Wall.`

Donc, ce -Walln'est pas parce que vous avez tout ce que vous avez. ;)


3

J'utilise parfois -spour un exécutable beaucoup plus petit:

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

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


6
vous devriez simplement exécuter stripsur votre binaire, de cette façon vous pouvez avoir un binaire avec des informations de débogage, supprimez-le plus tard pour la distribution.
Hasturkun

Oui, cela stripfonctionne aussi mais -speut être plus rapide et plus facile, même si ce n'est pas aussi élaboré que de courirstrip
Vasiliy Sharapov

3

Bien que cette réponse puisse être légèrement hors sujet et que la question soit un +1 digne de ma part, puisque

Je suis particulièrement intéressé par les avertissements supplémentaires et / ou par la transformation des avertissements en erreurs dans certains cas afin de minimiser absolument toute incompatibilité de type accidentelle.
il y a un outil qui devrait attraper TOUTES les erreurs et les erreurs potentielles qui peuvent ne pas être évidentes, il y a une attelle qui, à mon humble avis, fait un travail bien meilleur pour attraper les erreurs par rapport à gcc ou à tout autre compilateur d'ailleurs. C'est un outil digne d'avoir dans votre coffre à outils.

La vérification statique via un outil de type lint tel que splint, aurait dû faire partie d'une chaîne d'outils de compilateur.


Il montre toujours qu'une erreur ne peut pas classer le fichier de préprocesseur dans C: \ include, je ne sais pas quoi faire
Suraj Jain

2

Je suis particulièrement intéressé par les avertissements supplémentaires,

En plus de -Wall, l' option -Wou -Wextra( -Wfonctionne avec les anciennes versions de gcc ainsi que les plus récentes; les versions plus récentes prennent en charge le nom alternatif -Wextra, qui signifie la même chose, mais est plus descriptif) permet divers avertissements supplémentaires.

Il y a aussi encore plus d'avertissements qui ne sont activés par aucun de ceux-ci, généralement pour des choses qui sont plus douteuses. L'ensemble des options disponibles dépend de la version de gcc que vous utilisez - consultez man gccou info gccpour plus de détails, ou consultez la documentation en ligne de la version de gcc qui vous intéresse. Et -pedanticémet tous les avertissements requis par la norme particulière utilisée (ce qui dépend sur d'autres options telles que -std=xxxou -ansi) et se plaint de l'utilisation des extensions gcc.

et / ou et transformer les avertissements en erreurs dans certains cas pour minimiser absolument toute discordance de type accidentelle.

-Werrortransforme tous les avertissements en erreurs. Je ne pense pas que gcc vous permette de faire cela de manière sélective pour des avertissements particuliers, cependant.

Vous constaterez probablement que vous devez être sélectif sur les avertissements activés par projet (surtout si vous utilisez -Werror), car les fichiers d'en-tête de bibliothèques externes peuvent en déclencher certains. ( -pedanticen particulier, a tendance à ne pas être utile à cet égard, d'après mon expérience.)


4
"Je ne pense pas que gcc vous permette de faire cela de manière sélective pour des avertissements particuliers, cependant." En fait, vous pouvez avec -Werror=some-warning.
Matthew Flaschen

0
  • -Wmissing-prototypes: Si une fonction globale est définie sans déclaration de prototype préalable.
  • -Wformat-security: Avertit des utilisations des fonctions de formatage qui représentent des problèmes de sécurité possibles. À l'heure actuelle, cela avertit des appels à printfet des scanffonctions où la chaîne de format n'est pas une chaîne littérale et il n'y a pas d'arguments de format

0
  • -Werror=return-type: Appliquer une erreur lorsque la fonction n'a pas de retour dans gcc. C'est /we4716dans Visual Studio.

  • -Werror=implicit-function-declaration: Appliquer une erreur lorsque la fonction est utilisée sans définie / non incluse. C'est /we4013dans Visual Studio.

  • -Werror=incompatible-pointer-types: Erreur Enfore lorsque le type d'un pointeur ne correspond pas au type de pointeur attendu. C'est /we4133dans Visual Studio.

En fait, j'aimerais garder mon code C multiplateforme, et j'utilise CMake, et je mets les cflags fournis dans CMakeLists.txt comme:

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()
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.