Come disabilitare gli avvisi GCC per alcune righe di codice


220

In Visual C ++, è possibile utilizzare #pragma warning (disable: ...). Inoltre ho scoperto che in GCC è possibile sovrascrivere i flag del compilatore di file . Come posso fare questo per "riga successiva", o con la semantica push / pop attorno alle aree di codice usando GCC?


1
possibile duplicato di disabilitare specifici avvisi in gcc - Spiacenti, in realtà quella domanda è una copia (ma non chiusa). Questo sembra essere quello mostrato in "Correlati". Ad ogni modo, questo è stato chiesto e risposto più volte su SO.
Tyler McHenry,

1
@paxdiablo: sto facendo il contrario. Ho alzato il livello di avviso molto alto e voglio eliminare gli avvisi riga per riga che ho verificato di essere a posto.
Matt Joiner,

4
@Tyler McHenry: Se hai controllato più attentamente potresti notare che la domanda collegata contiene una soluzione per file, precisamente quella che ho menzionato nella mia domanda come insoddisfacente (ho persino rubato il collegamento).
Matt Joiner,

6
@paxdiablo, i compilatori danno falsi positivi, a volte vuoi compilare con -Werror ma non hai questi falsi positivi che bloccano una build. così disabilitando i casi spesifici e commentando il perché - in alcuni casi ha senso. Ci sono anche altri casi in cui questo potrebbe essere utile, come il codice di generazione automatica che produce avvisi innocui che non sono così facili da inserire e modificare (poiché il codice viene generato), anche se in quel caso è più probabile che la disabilitazione per file la soluzione.
ideasman42

Risposte:


221

Sembra che questo possa essere fatto . Non riesco a determinare la versione di GCC che è stata aggiunta, ma era prima del giugno 2010.

Ecco un esempio:

#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 */

14
uno pushe due pops - potrebbe esserne un altro pushmancante all'inizio?
abisso

37
"#pragma push diagnostico GCC #pragma pop diagnostico GCC Fa in modo che GCC ricordi lo stato della diagnostica a ogni push e lo ripristini su quel punto in corrispondenza di ogni pop. Se un pop non ha push corrispondenti, le opzioni della riga di comando vengono ripristinate. " - dal manuale GCC: gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html
bobpaul

11
Per riferimento, la versione 4.4.3 di gcc supporta errori / avvertimenti / ignorati, ma non push / pop
frankster

12
La prima versione di GCC con push / pop diagnostici è GCC 4.6.4 . L'ho determinato guardando la sezione Diagnostic-Pragmas.html # Diagnostic-Pragmas per ogni versione di GCC nella Documentazione GCC
bitek,

5
È un peccato che non funzioni nella pratica. In alcuni casi, produce più avvisi. O forse, più correttamente, non funziona in pratica per GCC da 4.7 a 5.1. Vedi, ad esempio, GCC non onora la "diagnostica pragma GCC" per mettere a tacere gli avvisi .
JWW

108

Per escludere tutto, questo è un esempio di disabilitazione temporanea di un avviso:

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

È possibile controllare la documentazione GCC sui pragmi diagnostici per maggiori dettagli.


2
Dovrebbe funzionare, ma il mio gcc-4.9ignora completamente questa riga.
Aleksei Petrenko,

31

TL; DR : se funziona, evita o usa specificatori come __attribute__, altrimenti _Pragma.

Questa è una versione breve del mio articolo sul blog Sopprimere gli avvisi in GCC e Clang .

Considera quanto segue Makefile

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

.PHONY: all
all: puts

per creare il seguente puts.ccodice sorgente

#include <stdio.h>

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

Non verrà compilato perché argcnon è utilizzato e le impostazioni sono hardcore ( -W -Wall -pedantic -Werror).

Ci sono 5 cose che potresti fare:

  • Migliora il codice sorgente, se possibile
  • Utilizzare un identificatore di dichiarazione, ad esempio __attribute__
  • Uso _Pragma
  • Uso #pragma
  • Utilizzare un'opzione della riga di comando.

Migliorare la fonte

Il primo tentativo dovrebbe essere verificare se il codice sorgente può essere migliorato per eliminare l'avviso. In questo caso non vogliamo cambiare l'algoritmo solo per questo, come argcè ridondante con !*argv( NULLdopo l'ultimo elemento).

Usando un identificatore di dichiarazione, come __attribute__

#include <stdio.h>

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

Se sei fortunato, lo standard fornisce un identificatore per la tua situazione, come _Noreturn.

__attribute__è un'estensione GCC proprietaria (supportata da Clang e anche da altri compilatori armcc) e non sarà compresa da molti altri compilatori. Inserisci __attribute__((unused))una macro se vuoi un codice portatile.

_Pragma operatore

_Pragmapuò essere usato in alternativa a #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")

Il vantaggio principale _Pragmadell'operatore è che potresti inserirlo all'interno di macro, cosa impossibile con la #pragmadirettiva.

Unico inconveniente: è quasi una bomba tattica, in quanto funziona in linea anziché in dichiarazione.

L' _Pragmaoperatore è stato introdotto nel C99.

#pragma direttiva.

Potremmo modificare il codice sorgente per sopprimere l'avviso per una regione di codice, in genere un'intera funzione:

#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

Unico inconveniente: è quasi una bomba tattica, in quanto funziona in linea anziché in dichiarazione.

Si noti che esiste una sintassi simile in clang .

Sopprimendo l'avviso sulla riga di comando per un singolo file

Potremmo aggiungere la seguente riga al Makefileper sopprimere l'avviso specificamente per put:

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

.PHONY: all
all: puts

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

Questo probabilmente non è quello che vuoi nel tuo caso particolare, ma può aiutare altre letture che si trovano in situazioni simili.


2
ri: improving the sourcefunzionerebbe anche per cambiare la dichiarazione di main in int main(int, const char* argv[]) { ... }non dando un nome all'argomento, dici al compilatore che non sarà usato.
Jesse Chisholm,

1
@JesseChisholm non è possibile omettere il nome del parametro nella definizione della funzione. Vedi 6.9.1 Definizioni delle funzioni di ISO / IEC9899, ​​§5 "Se il dichiarante include un elenco di tipi di parametri, la dichiarazione di ciascun parametro deve includere un identificatore [...]" E correttamente, quindi il codice sarebbe rifiutato da gcce clang.
Christian Hujer,

1
Un altro modello è quello di fare solo un cast della variabile da annullare. In effetti, in un progetto ho visto la seguente macro: #define UNUSED(x) ((void)x)utilizzata per mettere a tacere gli avvisi. Penso che fosse in ReactOS?
Paul Stelian,

1
Non penso che ti serva una barra rovesciata dopo questo, no? _Pragma("GCC diagnostic pop") \ dovrebbe essere solo _Pragma("GCC diagnostic pop")penso.
Gabriel Staples,

1
@GabrielStaples Esatto, grazie per averlo notato, ho aggiornato la risposta.
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

Questo dovrebbe fare il trucco per gcc, clang e msvc

Può essere chiamato con es:

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

vedi https://gcc.gnu.org/onlinedocs/cpp/Pragmas.html , http://clang.llvm.org/docs/UsersManual.html#controlling-diagnostics-via-pragmas e https://msdn.microsoft .com / de-DE / library / d9x1s805.aspx per maggiori dettagli

È necessario almeno la versione 4.02 per usare questo tipo di pragmi per gcc, non si è sicuri di msvc e del clang delle versioni.

Sembra che la gestione del pragma push pop per gcc sia un po 'rotta. Se si attiva nuovamente l'avviso, viene comunque visualizzato l'avviso per il blocco all'interno del blocco DISABLE_WARNING / ENABLE_WARNING. Per alcune versioni di gcc funziona, per altre no.


3
Da vero MVP
zeboidlund

19
#pragma GCC diagnostic ignored "-Wformat"

Sostituisci "-Wformat" con il nome del tuo flag di avviso.

AFAIK non c'è modo di usare la semantica push / pop per questa opzione.


4
È un peccato che non funzioni nella pratica. In alcuni casi, produce più avvisi. O forse, più correttamente, non funziona in pratica per GCC da 4.7 a 5.1. Vedi, ad esempio, GCC non onora la "diagnostica pragma GCC" per mettere a tacere gli avvisi .
JWW

6

Ho avuto lo stesso problema con le librerie esterne come le intestazioni ROS. Mi piace usare le seguenti opzioni in CMakeLists.txt per una compilazione più rigorosa:

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

Tuttavia, ciò causa tutti i tipi di errori pedanti anche nelle librerie incluse esternamente. La soluzione è disabilitare tutti gli avvisi pedanti prima di includere librerie esterne e riattivare in questo modo:

//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

2
Questo non dovrebbe essere gestito meglio con le directory di sistema di gcc ?
Red XIII,

@RedXIII - sì, è un'opzione se puoi fare un elenco di tali directory e specificare nella riga di comando di gcc. Tuttavia, molte volte il compilatore viene invocato in profondità nella pipeline o non hai molto controllo su come qualcun altro dovrebbe compilare il tuo codice. In quei casi sopra è probabilmente una soluzione migliore.
Shital Shah,

5

So che la domanda riguarda GCC, ma per le persone che cercano come farlo in altri compilatori e / o multipli ...

TL; DR

Potresti dare un'occhiata a Hedley , che è una singola intestazione C / C ++ di dominio pubblico che ho scritto che fa un sacco di queste cose per te. Metterò una breve sezione su come usare Hedley per tutto questo alla fine di questo post.

Disabilitare l'avviso

#pragma warning (disable: …) ha equivalenti nella maggior parte dei compilatori:

  • MSVC: #pragma warning(disable:4996)
  • GCC: #pragma GCC diagnostic ignored "-W…"dove i puntini di sospensione sono il nome dell'avvertimento; es , #pragma GCC diagnostic ignored "-Wdeprecated-declarations.
  • clang: #pragma clang diagnostic ignored "-W…". La sintassi è sostanzialmente la stessa di GCC e molti dei nomi degli avvisi sono gli stessi (anche se molti non lo sono).
  • Compilatore Intel C: utilizzare la sintassi MSVC, ma tenere presente che i numeri di avviso sono totalmente diversi. Esempio: #pragma warning(disable:1478 1786).
  • IGP: esiste un diag_suppresspragma:#pragma diag_suppress 1215,1444
  • TI: Esiste un diag_suppresspragma con la stessa sintassi (ma numeri di avvertimento diversi!) Di IGP:pragma diag_suppress 1291,1718
  • Oracle Developer Studio (suncc): esiste un error_messagespragma. Stranamente, gli avvisi sono diversi per i compilatori C e C ++. Entrambi disabilitano sostanzialmente gli stessi avvertimenti:
    • C: #pragma error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)
    • C ++: #pragma error_messages(off,symdeprecated,symdeprecated2)
  • IAR: usa anche diag_suppresscome IGP e TI, ma la sintassi è diversa. Alcuni dei numeri di avviso sono gli stessi, ma altri ho diverguto:#pragma diag_suppress=Pe1444,Pe1215
  • Pelles C: simile a MSVC, anche se i numeri sono ancora diversi #pragma warn(disable:2241)

Per la maggior parte dei compilatori è spesso una buona idea controllare la versione del compilatore prima di provare a disabilitarla, altrimenti finirai per attivare un altro avviso. Ad esempio, GCC 7 ha aggiunto il supporto per l' -Wimplicit-fallthroughavvertimento, quindi se ti interessa GCC prima di 7 dovresti fare qualcosa di simile

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

Per clang e compilatori basati su clang come le versioni più recenti di XL C / C ++ e armclang, puoi verificare se il compilatore è a conoscenza di un particolare avviso utilizzando la __has_warning()macro.

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

Ovviamente devi anche verificare se __has_warning()esiste la macro:

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

Potresti essere tentato di fare qualcosa del genere

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

Quindi puoi usarlo __has_warningun po 'più facilmente. Clang suggerisce persino qualcosa di simile per la __has_builtin()macro nel loro manuale. Non farlo . Un altro codice può verificare __has_warninge ricorrere al controllo delle versioni del compilatore se non esiste e, se lo definisci, __has_warningne spezzerai il codice. Il modo giusto per farlo è creare una macro nel tuo spazio dei nomi. Per esempio:

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

Quindi puoi fare cose come

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

Spingendo e scoppiando

Molti compilatori supportano anche un modo per inviare e far apparire gli avvisi in una pila. Ad esempio, questo disabiliterà un avviso su GCC per una riga di codice, quindi lo restituirà al suo stato precedente:

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

Ovviamente non c'è molto accordo tra i compilatori sulla sintassi:

  • GCC 4.6+: #pragma GCC diagnostic push/#pragma GCC diagnostic pop
  • clang: #pragma clang diagnostic push/#pragma diagnostic pop
  • Intel 13+ (e probabilmente prima): #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+ (e probabilmente prima): #pragma warning(push)/#pragma warning(pop)

Se la memoria serve, per alcune versioni molto vecchie di GCC (come 3.x, IIRC) i pragmi push / pop dovevano essere al di fuori della funzione.

Nascondere i dettagli cruenti

Per la maggior parte dei compilatori è possibile nascondere la logica alla base delle macro _Pragma, introdotta in C99. Anche in modalità non C99, la maggior parte dei compilatori supporta _Pragma; la grande eccezione è MSVC, che ha una propria __pragmaparola chiave con una sintassi diversa. Lo standard _Pragmaaccetta una stringa, la versione di Microsoft no:

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

È approssimativamente equivalente, una volta preelaborato, a

#pragma foo

Questo ci consente di creare macro in modo da poter scrivere codice come

MY_DIAGNOSTIC_PUSH
MY_DIAGNOSTIC_DISABLE_DEPRECATED
call_deprecated_function();
MY_DIAGNOSTIC_POP

E nascondi tutti i brutti controlli di versione nelle definizioni macro.

Il modo semplice: Hedley

Ora che hai capito la meccanica di come fare cose come questa in modo portabile mantenendo pulito il tuo codice, capisci cosa fa uno dei miei progetti, Hedley . Invece di scavare tra tonnellate di documentazione e / o installare quante più versioni di quanti compilatori puoi testare, puoi semplicemente includere Hedley (è una singola intestazione C / C ++ di dominio pubblico) e farla finita. Per esempio:

#include "hedley.h"

HEDLEY_DIAGNOSTIC_PUSH
HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
call_deprecated();
HEDLEY_DIAGNOSTIC_POP

Disabiliterò l'avviso di chiamare una funzione deprecata su GCC, clang, ICC, PGI, MSVC, TI, IAR, ODS, Pelles e forse altri (probabilmente non mi preoccuperò di aggiornare questa risposta mentre aggiorno Hedley). E, sui compilatori che non sono noti per funzionare, le macro verranno preelaborate a zero, quindi il tuo codice continuerà a funzionare con qualsiasi compilatore. Naturalmente HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATEDnon è l'unico avvertimento di cui Hedley è a conoscenza, né disabilita gli avvisi che tutto ciò che Hedley può fare, ma spero che tu abbia l'idea.


3

Invece di mettere a tacere gli avvisi, lo stile gcc è di solito usare costrutti C standard o l' __attribute__estensione per dire al compilatore di più sulla tua intenzione. Ad esempio, l'avvertenza sull'assegnazione utilizzata come condizione viene soppressa inserendo l'incarico tra parentesi, ovvero if ((p=malloc(cnt)))anziché if (p=malloc(cnt)). Gli avvisi su argomenti di funzioni inutilizzati possono essere soppressi da alcuni strani __attribute__che non riesco mai a ricordare, o da autoassegnazione, ecc. Ma generalmente preferisco solo disabilitare globalmente qualsiasi opzione di avviso che generi avvisi per cose che si verificano nel codice corretto.


2
Può darsi. Il mio intento non è quello di dimostrare alcun modello di caso generale, piuttosto un'osservazione su quale sia la filosofia di gcc sulla soppressione degli avvertimenti.
R .. GitHub FERMA AIUTANDO ICE

il compilatore si comporta diversamente con gli avvisi w / r / t con le parentesi aggiunte?!?! ?? !!!! WOW! Questo è inaspettato.
Jason S,

1
@JasonS the parens non cambia il comportamento del compilatore con gli avvertimenti, ciò che fa è cambiare la semantica dell'istruzione. Le parentesi extra fanno sì che il compilatore finisca l'assegnazione e mantenga il suo valore finale come espressione, che non merita alcun avvertimento. Se vuoi chiarezza, potresti dire if ((p=malloc(cnt)) != NULL) ...che è quello che sta facendo il compilatore dietro le quinte.
Jesse Chisholm,

@JesseChisholm: Non penso che la tua spiegazione sia accurata.
R .. GitHub FERMA AIUTANDO ICE

3

Per coloro che hanno trovato questa pagina alla ricerca di un modo per farlo in IAR, prova questo:

#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

Vedere http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0472m/chr1359124244797.html per riferimento.

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.