Comment désactiver les avertissements GCC pour quelques lignes de code

220

En Visual C ++, il est possible d'utiliser #pragma warning (disable: ...). J'ai également constaté que dans GCC, vous pouvez remplacer les drapeaux du compilateur par fichier . Comment est-ce que je peux faire ceci pour la "ligne suivante", ou avec la sémantique push / pop autour des zones de code en utilisant GCC?

Matt Joiner
la source
1
doublon possible de désactiver des avertissements spécifiques dans gcc - Oups, en fait cette question elle-même est une dupe (mais pas fermée). Il se trouve que c'est celui qui est apparu sous "Connexes". Quoi qu'il en soit, cela a été demandé et répondu plusieurs fois sur SO.
Tyler McHenry
1
@paxdiablo: Je fais l'inverse. J'ai augmenté le niveau d'avertissement très haut et je veux écraser les avertissements ligne par ligne que j'ai vérifié.
Matt Joiner
4
@Tyler McHenry: Si vous avez vérifié plus attentivement, vous remarquerez peut-être que la question liée contient une solution par fichier, précisément celle que j'ai mentionnée dans ma propre question comme insatisfaisante (j'ai même volé le lien).
Matt Joiner
6
@paxdiablo, les compilateurs donnent des faux positifs, parfois vous voulez compiler avec -Werror mais ne pas avoir ces faux positifs bloquant une construction. donc désactiver des cas spécifiques et expliquer pourquoi - est logique dans certains cas. Il existe également d'autres cas où cela pourrait être pratique - comme le code auto-générateur qui génère des avertissements inoffensifs qui ne sont pas si faciles à saisir et à modifier (car le code est généré), bien que dans ce cas, la désactivation par fichier soit plus susceptible d'être la solution.
ideasman42

Réponses:

221

Il semble que cela puisse être fait . Je ne peux pas déterminer la version de GCC qui a été ajoutée, mais c'était avant juin 2010.

Voici un exemple:

#pragma GCC diagnostic error "-Wuninitialized"
    foo(a);         /* error is given for this one */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wuninitialized"
    foo(b);         /* no diagnostic for this one */
#pragma GCC diagnostic pop
    foo(c);         /* error is given for this one */
#pragma GCC diagnostic pop
    foo(d);         /* depends on command line options */
Matt Joiner
la source
14
un pushet deux pops - peut-être un autre pushau début est manquant?
abyss.7
37
"#pragma GCC diagnostic push #pragma GCC diagnostic pop Permet à GCC de se souvenir de l'état des diagnostics à chaque push, et de restaurer ce point à chaque pop. Si un pop n'a pas de push correspondant, les options de ligne de commande sont restaurées. " - extrait du manuel du GCC: gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html
bobpaul
11
Pour référence, la version 4.4.3 de gcc prend en charge l'erreur / avertissement / ignoré, mais pas push / pop
frankster
12
La première version de GCC qui avait un diagnostic push / pop est GCC 4.6.4 . J'ai déterminé cela en consultant la section Diagnostic-Pragmas.html # Diagnostic-Pragmas pour chaque version de GCC
bitek
5
C'est dommage que cela ne fonctionne pas dans la pratique. Dans certains cas, il génère plus d'avertissements. Ou peut-être, plus correctement, cela ne fonctionne pas dans la pratique pour GCC 4.7 à 5.1. Voir, par exemple, GCC n'honore pas le «diagnostic pragma GCC» pour faire taire les avertissements .
2015
108

Pour tout supprimer, voici un exemple de désactivation temporaire d' un avertissement:

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-result"
    write(foo, bar, baz);
#pragma GCC diagnostic pop

Vous pouvez consulter la documentation GCC sur les pragmas de diagnostic pour plus de détails.

Ian Pilcher
la source
2
Devrait fonctionner, mais mon gcc-4.9ignore complètement cette ligne.
Aleksei Petrenko
31

TL; DR : si cela fonctionne, évitez ou utilisez des spécificateurs comme __attribute__, sinon_Pragma .

Ceci est une version courte de mon article de blog Suppression des avertissements dans GCC et Clang .

Considérer ce qui suit Makefile

CPPFLAGS:=-std=c11 -W -Wall -pedantic -Werror

.PHONY: all
all: puts

pour construire le puts.ccode source suivant

#include <stdio.h>

int main(int argc, const char *argv[])
{
    while (*++argv) puts(*argv);
    return 0;
}

Il ne se compilera pas car il argcn'est pas utilisé et les paramètres sont inconditionnels (-W -Wall -pedantic -Werror ).

Vous pouvez faire 5 choses:

  • Améliorez le code source, si possible
  • Utilisez un spécificateur de déclaration, comme __attribute__
  • Utilisation _Pragma
  • Utilisation #pragma
  • Utilisez une option de ligne de commande.

Améliorer la source

La première tentative devrait être de vérifier si le code source peut être amélioré pour se débarrasser de l'avertissement. Dans ce cas, nous ne voulons pas changer l'algorithme juste à cause de cela, comme argcc'est redondant avec !*argv( NULLaprès le dernier élément).

Utilisation d'un spécificateur de déclaration, comme __attribute__

#include <stdio.h>

int main(__attribute__((unused)) int argc, const char *argv[])
{
    while (*++argv) puts(*argv);
    return 0;
}

Si vous avez de la chance, la norme fournit un spécificateur pour votre situation, comme _Noreturn.

__attribute__est une extension GCC propriétaire (prise en charge par Clang et certains autres compilateurs comme armcc) et ne sera pas comprise par de nombreux autres compilateurs. Mettez à l' __attribute__((unused))intérieur d'une macro si vous voulez du code portable.

_Pragma opérateur

_Pragmapeut être utilisé comme alternative à #pragma.

#include <stdio.h>

_Pragma("GCC diagnostic push")
_Pragma("GCC diagnostic ignored \"-Wunused-parameter\"")

int main(int argc, const char *argv[])
{
    while (*++argv) puts(*argv);
    return 0;
}
_Pragma("GCC diagnostic pop")

Le principal avantage de l' _Pragmaopérateur est qu'il peut être placé dans des macros, ce qui n'est pas possible avec la #pragmadirective.

Inconvénient: c'est presque un nucléaire tactique, car il fonctionne en ligne plutôt qu'en déclaration.

L' _Pragmaopérateur a été introduit en C99.

#pragma directif.

Nous pourrions changer le code source pour supprimer l'avertissement pour une région de code, généralement une fonction entière:

#include <stdio.h>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
int main(int argc, const char *argv[])
{
    while (*++argc) puts(*argv);
    return 0;
}
#pragma GCC diagnostic pop

Inconvénient: c'est presque un nucléaire tactique, car il fonctionne en ligne plutôt qu'en déclaration.

Notez qu'une syntaxe similaire existe dans clang .

Suppression de l'avertissement sur la ligne de commande pour un seul fichier

Nous pourrions ajouter la ligne suivante à Makefilepour supprimer l'avertissement spécifiquement pour les put :

CPPFLAGS:=-std=c11 -W -Wall -pedantic -Werror

.PHONY: all
all: puts

puts.o: CPPFLAGS+=-Wno-unused-parameter

Ce n'est probablement pas ce que vous voulez dans votre cas particulier, mais cela peut aider d'autres lectures qui se trouvent dans des situations similaires.

Christian Hujer
la source
2
re: improving the sourceil serait également utile de changer la déclaration de main int main(int, const char* argv[]) { ... }en ne donnant pas de nom à l'argument, vous dites au compilateur qu'il ne sera pas utilisé.
Jesse Chisholm
1
@JesseChisholm omettre le nom du paramètre lors de la définition de la fonction n'est pas possible. Voir 6.9.1 Définitions des fonctions de l'ISO / CEI9899, ​​§5 "Si le déclarant inclut une liste de types de paramètres, la déclaration de chaque paramètre doit inclure un identifiant […]" Et correctement pour que le code soit rejeté gccaussi bien que clang.
Christian Hujer
1
Un autre modèle consiste à simplement transtyper la variable à annuler. En fait, j'ai vu dans un projet la macro suivante: #define UNUSED(x) ((void)x)utilisée pour faire taire les avertissements. Je pense que c'était dans ReactOS?
Paul Stelian
1
Je ne pense pas que vous ayez besoin de la barre oblique inverse après cela, non? _Pragma("GCC diagnostic pop") \ devrait juste être _Pragma("GCC diagnostic pop")je pense.
Gabriel Staples
1
@GabrielStaples C'est exact, merci de l'avoir remarqué, j'ai mis à jour la réponse.
Christian Hujer
20
#define DIAG_STR(s) #s
#define DIAG_JOINSTR(x,y) DIAG_STR(x ## y)
#ifdef _MSC_VER
#define DIAG_DO_PRAGMA(x) __pragma (#x)
#define DIAG_PRAGMA(compiler,x) DIAG_DO_PRAGMA(warning(x))
#else
#define DIAG_DO_PRAGMA(x) _Pragma (#x)
#define DIAG_PRAGMA(compiler,x) DIAG_DO_PRAGMA(compiler diagnostic x)
#endif
#if defined(__clang__)
# define DISABLE_WARNING(gcc_unused,clang_option,msvc_unused) DIAG_PRAGMA(clang,push) DIAG_PRAGMA(clang,ignored DIAG_JOINSTR(-W,clang_option))
# define ENABLE_WARNING(gcc_unused,clang_option,msvc_unused) DIAG_PRAGMA(clang,pop)
#elif defined(_MSC_VER)
# define DISABLE_WARNING(gcc_unused,clang_unused,msvc_errorcode) DIAG_PRAGMA(msvc,push) DIAG_DO_PRAGMA(warning(disable:##msvc_errorcode))
# define ENABLE_WARNING(gcc_unused,clang_unused,msvc_errorcode) DIAG_PRAGMA(msvc,pop)
#elif defined(__GNUC__)
#if ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406
# define DISABLE_WARNING(gcc_option,clang_unused,msvc_unused) DIAG_PRAGMA(GCC,push) DIAG_PRAGMA(GCC,ignored DIAG_JOINSTR(-W,gcc_option))
# define ENABLE_WARNING(gcc_option,clang_unused,msvc_unused) DIAG_PRAGMA(GCC,pop)
#else
# define DISABLE_WARNING(gcc_option,clang_unused,msvc_unused) DIAG_PRAGMA(GCC,ignored DIAG_JOINSTR(-W,gcc_option))
# define ENABLE_WARNING(gcc_option,clang_option,msvc_unused) DIAG_PRAGMA(GCC,warning DIAG_JOINSTR(-W,gcc_option))
#endif
#endif

Cela devrait faire l'affaire pour gcc, clang et msvc

Peut être appelé avec par exemple:

DISABLE_WARNING(unused-variable,unused-variable,42)
[.... some code with warnings in here ....]
ENABLE_WARNING(unused-variable,unused-variable,42)

voir https://gcc.gnu.org/onlinedocs/cpp/Pragmas.html , http://clang.llvm.org/docs/UsersManual.html#controlling-diagnostics-via-pragmas et https://msdn.microsoft .com / de-DE / library / d9x1s805.aspx pour plus de détails

Vous avez besoin d'au moins la version 4.02 pour utiliser ce genre de pragmas pour gcc, vous n'êtes pas sûr de msvc et clang sur les versions.

Il semble que la gestion du pragma push pop pour gcc soit un peu cassée. Si vous réactivez l'avertissement, vous obtenez toujours l'avertissement pour le bloc qui était à l'intérieur du bloc DISABLE_WARNING / ENABLE_WARNING. Pour certaines versions de gcc, cela fonctionne, pour d'autres non.

Martin Gerhardy
la source
3
You da real MVP
zeboidlund
19
#pragma GCC diagnostic ignored "-Wformat"

Remplacez "-Wformat" par le nom de votre indicateur d'avertissement.

AFAIK il n'y a aucun moyen d'utiliser la sémantique push / pop pour cette option.

Joe D
la source
4
C'est dommage que cela ne fonctionne pas dans la pratique. Dans certains cas, il génère plus d'avertissements. Ou peut-être, plus correctement, cela ne fonctionne pas dans la pratique pour GCC 4.7 à 5.1. Voir, par exemple, GCC n'honore pas le «diagnostic pragma GCC» pour faire taire les avertissements .
2015 à 7h01
6

J'ai eu le même problème avec les bibliothèques externes comme les en-têtes ROS. J'aime utiliser les options suivantes dans CMakeLists.txt pour une compilation plus stricte:

set(CMAKE_CXX_FLAGS "-std=c++0x -Wall -Wextra -Wstrict-aliasing -pedantic -Werror -Wunreachable-code ${CMAKE_CXX_FLAGS}")

Cependant, cela provoque également toutes sortes d'erreurs pédantes dans les bibliothèques incluses en externe. La solution est de désactiver tous les avertissements pédants avant d'inclure des bibliothèques externes et de les réactiver comme ceci:

//save compiler switches
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"

//Bad headers with problem goes here
#include <ros/ros.h>
#include <sensor_msgs/LaserScan.h>

//restore compiler switches
#pragma GCC diagnostic pop
Shital Shah
la source
2
Cela ne devrait-il pas être mieux géré par les répertoires système de gcc ?
Red XIII
@RedXIII - oui, c'est une option si vous pouvez faire la liste de ces répertoires et spécifier dans la ligne de commande gcc. Cependant, plusieurs fois, le compilateur est invoqué profondément dans le pipeline ou vous n'avez pas beaucoup de contrôle sur la façon dont quelqu'un d'autre devrait compiler votre code. Dans ces cas ci-dessus est probablement une meilleure solution.
Shital Shah
5

Je sais que la question concerne GCC, mais pour ceux qui cherchent comment faire cela dans d'autres compilateurs et / ou plusieurs…

TL; DR

Vous voudrez peut-être jeter un œil à Hedley , qui est un en-tête C / C ++ unique du domaine public que j'ai écrit et qui fait beaucoup de choses pour vous. Je mettrai une section rapide sur la façon d'utiliser Hedley pour tout cela à la fin de ce post.

Désactiver l'avertissement

#pragma warning (disable: …) a des équivalents dans la plupart des compilateurs:

  • MSVC: #pragma warning(disable:4996)
  • GCC: #pragma GCC diagnostic ignored "-W…"où les points de suspension sont le nom de l'avertissement; par exemple , #pragma GCC diagnostic ignored "-Wdeprecated-declarations.
  • clang: #pragma clang diagnostic ignored "-W…". La syntaxe est fondamentalement la même que celle de GCC, et de nombreux noms d'avertissement sont les mêmes (bien que beaucoup ne le soient pas).
  • Intel C Compiler: utilisez la syntaxe MSVC, mais gardez à l'esprit que les numéros d'avertissement sont totalement différents. Exemple: #pragma warning(disable:1478 1786).
  • IGP: Il y a un diag_suppresspragma:#pragma diag_suppress 1215,1444
  • TI: Il existe un diag_suppresspragma avec la même syntaxe (mais des numéros d'avertissement différents!) Que PGI:pragma diag_suppress 1291,1718
  • Oracle Developer Studio (suncc): il y a un error_messagespragma. Malheureusement, les avertissements sont différents pour les compilateurs C et C ++. Ces deux désactivent essentiellement les mêmes avertissements:
    • C: #pragma error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)
    • C ++: #pragma error_messages(off,symdeprecated,symdeprecated2)
  • IAR: utilise également diag_suppresscomme PGI et TI, mais la syntaxe est différente. Certains des numéros d'avertissement sont les mêmes, mais moi d'autres ont divergé:#pragma diag_suppress=Pe1444,Pe1215
  • Pelles C: similaire à MSVC, mais encore une fois les chiffres sont différents #pragma warn(disable:2241)

Pour la plupart des compilateurs, c'est souvent une bonne idée de vérifier la version du compilateur avant d'essayer de la désactiver, sinon vous finirez par déclencher un autre avertissement. Par exemple, GCC 7 a ajouté la prise en charge de l' -Wimplicit-fallthroughavertissement, donc si vous vous souciez de GCC avant 7, vous devriez faire quelque chose comme

#if defined(__GNUC__) && (__GNUC__ >= 7)
#  pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
#endif

Pour clang et les compilateurs basés sur clang tels que les versions plus récentes de XL C / C ++ et armclang, vous pouvez vérifier si le compilateur connaît un avertissement particulier à l'aide de la __has_warning()macro.

#if __has_warning("-Wimplicit-fallthrough")
#  pragma clang diagnostic ignored "-Wimplicit-fallthrough"
#endif

Bien sûr, vous devez également vérifier si la __has_warning()macro existe:

#if defined(__has_warning)
#  if __has_warning("-Wimplicit-fallthrough")
#    pragma clang diagnostic ignored "-Wimplicit-fallthrough"
#  endif
#endif

Vous pourriez être tenté de faire quelque chose comme

#if !defined(__has_warning)
#  define __has_warning(warning)
#endif

Vous pouvez donc utiliser __has_warningun peu plus facilement. Clang suggère même quelque chose de similaire pour la __has_builtin()macro dans leur manuel. Ne fais pas ça . Un autre code peut vérifier __has_warninget retomber sur la vérification des versions du compilateur s'il n'existe pas, et si vous définissez, __has_warningvous casserez leur code. La bonne façon de procéder consiste à créer une macro dans votre espace de noms. Par exemple:

#if defined(__has_warning)
#  define MY_HAS_WARNING(warning) __has_warning(warning)
#else
#  define MY_HAS_WARNING(warning) (0)
#endif

Ensuite, vous pouvez faire des choses comme

#if MY_HAS_WARNING(warning)
#  pragma clang diagnostic ignored "-Wimplicit-fallthrough"
#elif defined(__GNUC__) && (__GNUC__ >= 7)
#  pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
#endif

Pousser et éclater

De nombreux compilateurs prennent également en charge un moyen de pousser et d'afficher les avertissements sur une pile. Par exemple, cela désactivera un avertissement sur GCC pour une ligne de code, puis le ramènera à son état précédent:

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated"
call_deprecated_function();
#pragma GCC diagnostic pop

Bien sûr, il n'y a pas beaucoup d'accord entre les compilateurs sur la syntaxe:

  • GCC 4.6+: #pragma GCC diagnostic push/#pragma GCC diagnostic pop
  • clang: #pragma clang diagnostic push/#pragma diagnostic pop
  • Intel 13+ (et probablement plus tôt): #pragma warning(push)/#pragma warning(pop)
  • MSVC 15+ (VS 9.0 / 2008): #pragma warning(push)/#pragma warning(pop)
  • ARM 5.6+: #pragma push/#pragma pop
  • TI 8.1+: #pragma diag_push/#pragma diag_pop
  • Pelles C 2.90+ (et probablement plus tôt): #pragma warning(push)/#pragma warning(pop)

Si la mémoire est bonne, pour certaines versions très anciennes de GCC (comme 3.x, IIRC), les pragmas push / pop devaient être en dehors de la fonction.

Cacher les détails sanglants

Pour la plupart des compilateurs, il est possible de masquer la logique derrière les macros à l'aide de _Pragma, qui a été introduite dans C99. Même en mode non-C99, la plupart des compilateurs prennent en charge _Pragma; la grande exception est MSVC, qui a son propre __pragmamot-clé avec une syntaxe différente. La norme _Pragmaprend une chaîne, la version de Microsoft ne:

#if defined(_MSC_VER)
#  define PRAGMA_FOO __pragma(foo)
#else
#  define PRAGMA_FOO _Pragma("foo")
#endif
PRAGMA_FOO

Est à peu près équivalent, une fois prétraité, à

#pragma foo

Cela nous permet de créer des macros afin que nous puissions écrire du code comme

MY_DIAGNOSTIC_PUSH
MY_DIAGNOSTIC_DISABLE_DEPRECATED
call_deprecated_function();
MY_DIAGNOSTIC_POP

Et cachez tous les vilains contrôles de version dans les définitions de macro.

La manière la plus simple: Hedley

Maintenant que vous comprenez la mécanique de la façon de faire des trucs comme ça tout en gardant votre code propre, vous comprenez ce que fait un de mes projets, Hedley . Au lieu de fouiller dans des tonnes de documentation et / ou d'installer autant de versions du plus grand nombre de compilateurs que possible pour tester, vous pouvez simplement inclure Hedley (c'est un seul en-tête C / C ++ du domaine public) et en finir avec. Par exemple:

#include "hedley.h"

HEDLEY_DIAGNOSTIC_PUSH
HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
call_deprecated();
HEDLEY_DIAGNOSTIC_POP

Désactivera l'avertissement concernant l'appel d'une fonction obsolète sur GCC, clang, ICC, PGI, MSVC, TI, IAR, ODS, Pelles et peut-être d'autres (je ne prendrai probablement pas la peine de mettre à jour cette réponse car je mets à jour Hedley). Et, sur les compilateurs qui ne sont pas connus pour fonctionner, les macros seront prétraitées à rien, donc votre code continuera à fonctionner avec n'importe quel compilateur. Bien sûr, ce HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATEDn'est pas le seul avertissement dont Hedley est au courant, ni la désactivation des avertissements que tout Hedley peut faire, mais j'espère que vous avez l'idée.

nemequ
la source
3

Plutôt que de faire taire les avertissements, le style gcc consiste généralement à utiliser des constructions C standard ou l' __attribute__extension pour informer le compilateur de votre intention. Par exemple, l'avertissement concernant l'affectation utilisée comme condition est supprimé en mettant l'affectation entre parenthèses, c'est-à-dire if ((p=malloc(cnt)))au lieu de if (p=malloc(cnt)). Les avertissements sur les arguments de fonctions inutilisés peuvent être supprimés par des bizarreries dont __attribute__je ne me souviens jamais, ou par auto-affectation, etc. Mais généralement je préfère simplement désactiver globalement toute option d'avertissement qui génère des avertissements pour les choses qui se produiront dans le code correct.

R .. GitHub ARRÊTEZ D'AIDER LA GLACE
la source
2
Peut-être. Mon intention n'est pas de prouver un modèle de cas général, mais plutôt une observation sur ce que la philosophie de gcc sur la suppression des avertissements semble être.
R .. GitHub STOP HELPING ICE
le compilateur se comporte différemment avec des avertissements r / t avec des parenthèses ajoutées?!?! ?? !!!! HOU LA LA! C'est inattendu.
Jason S
1
@JasonS the parens ne change pas le comportement du compilateur par rapport aux avertissements, il modifie la sémantique de l'instruction. Les parens supplémentaires obligent le compilateur à terminer l'affectation et à conserver sa valeur finale en tant qu'expression, ce qui ne mérite aucun avertissement. Si vous voulez de la clarté, vous pouvez dire if ((p=malloc(cnt)) != NULL) ...que c'est ce que fait le compilateur en arrière-plan.
Jesse Chisholm
@JesseChisholm: Je ne pense pas que votre explication soit exacte.
R .. GitHub STOP HELPING ICE
3

Pour ceux qui ont trouvé cette page à la recherche d'un moyen de le faire dans IAR, essayez ceci:

#pragma diag_suppress=Pe177
void foo1( void )
{
   /* The following line of code would normally provoke diagnostic 
      message #177-D: variable "x" was declared but never referenced.
      Instead, we have suppressed this warning throughout the entire 
      scope of foo1(). 
   */
   int x;
}
#pragma diag_default=Pe177

Voir http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0472m/chr1359124244797.html pour référence.

Keron
la source