Come posso mettere a tacere un avviso sulle variabili non utilizzate?


237

Ho un'applicazione multipiattaforma e in alcune delle mie funzioni non vengono utilizzati tutti i valori passati alle funzioni. Quindi ricevo un avviso da GCC che mi dice che ci sono variabili non utilizzate.

Quale sarebbe il modo migliore per codificare l'avviso?

Un #ifdef attorno alla funzione?

#ifdef _MSC_VER
void ProcessOps::sendToExternalApp(QString sAppName, QString sImagePath, qreal qrLeft, qreal qrTop, qreal qrWidth, qreal qrHeight)
#else
void ProcessOps::sendToExternalApp(QString sAppName, QString sImagePath, qreal /*qrLeft*/, qreal /*qrTop*/, qreal /*qrWidth*/, qreal /*qrHeight*/)
#endif
{

Questo è così brutto ma sembra il modo in cui il compilatore preferirebbe.

O assegnare zero alla variabile alla fine della funzione? (che odio perché sta alterando qualcosa nel flusso del programma per mettere a tacere un avviso del compilatore).

C'è un modo corretto?


7
Mi sono appena reso conto che hai fatto una domanda simile lo scorso novembre. Questo è il motivo per cui sembra familiare! ;) stackoverflow.com/questions/308277/…
Alex B,

9
Perché non commentarli solo per entrambi i compilatori? Se l'arg non viene utilizzato su uno, probabilmente non verrà utilizzato sull'altro ...
Roger Lipscombe,

12
dovresti sapere che Qt ha una Q_UNUSEDmacro solo per questo. Dai un'occhiata nella documentazione.
Evan Teran,

1
La soluzione C funziona bene in C ++ anche: stackoverflow.com/a/3599170/1904815
JonnyJD

Il parametro Wno-unused potrebbe anche essere un'opzione se puoi avere flag di compilazione specifici del compilatore
Abominatore del codice

Risposte:


327

Puoi inserirlo (void)var;nell'espressione " " (non fa nulla) in modo che un compilatore lo veda utilizzato. Questo è portatile tra i compilatori.

Per esempio

void foo(int param1, int param2)
{
    (void)param2;
    bar(param1);
}

O,

#define UNUSED(expr) do { (void)(expr); } while (0)
...

void foo(int param1, int param2)
{
    UNUSED(param2);
    bar(param1);
}

22
+1 - vorrei documentare perché non usi la variabile anche se è presente.
Tobias Langner,

18
Ecco come Q_UNUSEDviene implementato in linea di principio.
Dmitry Volosnykh,

11
@Cameron puoi semplicemente omettere il nome del parametro in C ++. Se è modellato, non sarà usato in C, quindi non è necessario il trucco da cast a vuoto.
Alex B,

13
Basta #define UNUSED(expr) (void)(expr)dovrebbe funzionare anche (senza la do-while).
JonnyJD,

7
Mi chiedo come farlo per un modello variadico. In template<typename... Args> void f(const Args&... args)Non posso scrivere (void)args;o (void)args...;perché entrambi sono errori di sintassi.
Panzi,

101

In GCC e Clang puoi usare la __attribute__((unused))direttiva preprocessore per raggiungere il tuo obiettivo.
Per esempio:

int foo (__attribute__((unused)) int bar) {
   return 0;
}

1
Questa è la migliore soluzione per le funzioni di callback.
Sonic Atom

1
Supportato anche da clang: clang.llvm.org/docs/…
Alexander


39

La soluzione attuale è la migliore: commenta il nome del parametro se non la usi. Questo vale per tutti i compilatori, quindi non è necessario utilizzare il pre-processore per farlo appositamente per GCC.


7
Solo per rafforzare questa risposta - non è necessario il #ifdef, basta commentare i nomi dei parametri inutilizzati.
Quamrana,

4
Ho un caso in cui il parametro fa parte di un callback e commentarlo interrompe la compilazione (quindi non sono sicuro del perché g++sia un avvertimento a riguardo.) In tal caso, cosa consiglieresti?
Drew Noakes,

1
Immagina un metodo virtuale in linea con parametri non utilizzati / * commentato * /, il client dell'interfaccia non vedrà il nome del parametro durante il completamento automatico nella maggior parte degli IDE. In questo caso la soluzione UNUSED () è più conveniente, sebbene meno pulita.
cbuchart,

Penso che sia più semplice, commentare è molto chiaro
vedi il

26

Aggiornamento C ++ 17

In C ++ 17 otteniamo l'attributo [[maybe_unused]] che è coperto in [dcl.attr.unused]

Il token di attributo maybe_unused indica che un nome o un'entità è eventualmente intenzionalmente inutilizzato. Dovrà apparire al massimo una volta in ogni elenco di attributi e non dovrà essere presente alcuna clausola di argomento di attributo. ...

Esempio:

 [[maybe_unused]] void f([[maybe_unused]] bool thing1,
                        [[maybe_unused]] bool thing2) {
  [[maybe_unused]] bool b = thing1 && thing2;
    assert(b);
 }

Le implementazioni non devono avvisare che b non è utilizzato, indipendentemente dal fatto che sia definito o meno NDEBUG. —Esempio]

Per il seguente esempio:

int foo ( int bar) {
    bool unused_bool ;
    return 0;
}

Sia clang che gcc generano una diagnostica usando -Wall -Wextra sia per la barra che per unused_bool ( Guardalo dal vivo ).

Mentre aggiungi [[maybe_unused]] silenzia la diagnostica:

int foo ([[maybe_unused]] int bar) {
    [[maybe_unused]] bool unused_bool ;
    return 0;
}

vederlo dal vivo .

Prima di C ++ 17

In C ++ 11 una forma alternativa della UNUSEDmacro potrebbe essere formata usando un'espressione lambda ( via Ben Deane ) con una cattura della variabile non utilizzata:

#define UNUSED(x) [&x]{}()

L'invocazione immediata dell'espressione lambda dovrebbe essere ottimizzata, dato il seguente esempio:

int foo (int bar) {
    UNUSED(bar) ;
    return 0;
}

possiamo vedere in godbolt che la chiamata è ottimizzata via:

foo(int):
xorl    %eax, %eax
ret

5
Quindi menzioni C ++ 11 e riesci a presentare una macro ?! Ahia! Forse usare una funzione sarebbe più pulito? template <class T> inline void NOTUSED( T const & result ) { static_cast<void>(result); }Potresti anche usare un lambda nella funzione, suppongo.
Alexis Wilke,

godbolt è una grande risorsa
yano,

5
[&x]{}()in realtà non mette a tacere l'avvertimento, ma passa invece l'avviso dalla funzione chiamante al lambda. Ci vorrà del tempo prima che i compilatori lo identifichino come un avvertimento, ma clang-tidy si lamenta già di una variabile non utilizzata nell'elenco di acquisizione.
nVxx

25

Un modo ancora più pulito è semplicemente commentare i nomi delle variabili:

int main(int /* argc */, char const** /* argv */) {
  return 0;
}

8
Questo non va bene se hai doxygen e vuoi documentare i parametri.
Alexis Wilke,

18
@AlexisWilke: Quello si qualificherebbe come un bug in doxygen, IMO
6502

3
Puoi #definire YOUR_PROJECT_UNUSED (argname) in modo condizionale su #ifdef DOXYGEN in modo che doxygen possa vedere il nome e il vero compilatore no, tramite int main (int YOUR_PROJECT_UNUSED (argc), ...). Non favoloso, ma funziona.
mabraham,

Trovo molto doloroso commentare un blocco di codice con molti di questi commenti nidificati. (il compilatore si lamenta di ognuno).
Jeff McClintock,

@JeffMcClintock usa solo i commenti a riga singola. La maggior parte degli editor decenti supporta l'editing a blocchi verticali (ad esempio [Ctrl] + [V] in Vim). In caso contrario, utilizzare i #if 0 / #endifcommenti di blocco.
Ruslan,

24

Un collega mi ha appena indicato questa bella macro qui

Per semplicità includerò la macro qui sotto.

#ifdef UNUSED
#elif defined(__GNUC__) 
# define UNUSED(x) UNUSED_ ## x __attribute__((unused)) 
#elif defined(__LCLINT__) 
# define UNUSED(x) /*@unused@*/ x 
#else 
# define UNUSED(x) x 
#endif

void dcc_mon_siginfo_handler(int UNUSED(whatsig))

12
"nice" "macro" "c ++" - scegli 2.
Jeff McClintock,

23

non contrassegna questi avvisi per impostazione predefinita. Questo avviso deve essere stato attivato esplicitamente passando -Wunused-parameteral compilatore o implicitamente passando -Wall -Wextra(o eventualmente un'altra combinazione di flag).

Le avvertenze sui parametri non utilizzate possono essere semplicemente eliminate passando -Wno-unused-parameteral compilatore, ma si noti che questo flag di disabilitazione deve venire dopo eventuali flag di abilitazione per questo avviso nella riga di comando del compilatore, in modo che possa avere effetto.


2
Anche se questa potrebbe non essere la migliore risposta alla domanda (perché la domanda era come evitare l'avvertimento, non come disabilitarlo), questa risposta potrebbe essere la gente proveniente da google (come me) che stava cercando ("come per disabilitare questo avviso "). Quindi do +1, grazie per la tua risposta!
Mozzbozz,

13

modo macro-portatile e portatile per dichiarare uno o più parametri come inutilizzati:

template <typename... Args> inline void unused(Args&&...) {}

int main(int argc, char* argv[])
{
    unused(argc, argv);
    return 0;
}

Molto bene, ma tieni presente che questo richiede C ++ 11 (o più recente, ovviamente).
Paul R,

Ho votato verso il basso questa risposta perché non vorrei sacrificare il tempo di compilazione (utilizzando i modelli) solo per sbarazzarmi dell'avvertimento.
Konrad Kleine,

@KonradKleine: quanto tempo di compilazione potrebbe richiedere? Testando sul mio computer, posso eseguire un migliaio di queste chiamate non utilizzate () in un decimo di secondo.
Daniel McLaury,

@DanielMcLaury questa era solo una mia ipotesi e non ho fatto alcun esperimento.
Konrad Kleine,

8

L'uso delle direttive del preprocessore è considerato malvagio il più delle volte. Idealmente, vuoi evitarli come il parassita. Ricorda che far capire al compilatore il tuo codice è facile, permettere ad altri programmatori di capire il tuo codice è molto più difficile. Qualche decina di casi come questo qua e là rende molto difficile la lettura da soli in seguito o per gli altri in questo momento.

Un modo potrebbe essere quello di riunire i parametri in una sorta di classe di argomenti. È quindi possibile utilizzare solo un sottoinsieme delle variabili (equivalente alla propria assegnazione 0) o avere diverse specializzazioni di tale classe di argomenti per ciascuna piattaforma. Questo potrebbe tuttavia non valerne la pena, è necessario analizzare se si adatterebbe.

Se riesci a leggere modelli impossibili, potresti trovare suggerimenti avanzati nel libro "Eccezionale C ++". Se le persone che leggono il tuo codice potrebbero ottenere il loro skillset per comprendere le cose folli insegnate in quel libro, allora avresti un bellissimo codice che può anche essere facilmente letto. Il compilatore sarebbe anche ben consapevole di ciò che stai facendo (invece di nascondere tutto con la preelaborazione)


5
"L'uso delle direttive del preprocessore è considerato malvagio il più delle volte." Veramente? Da chi?
Graeme Perrow,

12
Da chiunque abbia a cuore l'ambito, essere in grado di eseguire correttamente il debug o la propria sanità mentale.
Bill,

2
@Graeme, sembra innocente quando ne vediamo solo 4 righe, ma diffonderlo provoca mal di testa. #ifdef ti consente sostanzialmente di inserire più versioni di un codice sorgente di cui il compilatore ne vedrà solo una. Come menziona Bill, rende anche più difficile il debug. Ho letto della malvagità delle direttive sui preprocessori in diversi libri e blog, oltre a averlo sperimentato da solo. Certo, tutto è relativo. A volte le direttive del preprocessore hanno semplicemente senso perché qualsiasi altra cosa avrebbe conseguenze peggiori, e il mio punto è qui solo che dovrebbe essere evitato dove possibile.
Ben Dadsetan,

1
L'uso eccessivo è negativo, ma definirei #define UNUSED(expr) (void)(expr)appropriato.
JonnyJD,

7

Innanzitutto l'avviso viene generato dalla definizione della variabile nel file di origine e non nel file di intestazione. L'intestazione può rimanere incontaminata e dovrebbe, poiché potresti usare qualcosa come doxygen per generare la documentazione API.

Presumo che tu abbia un'implementazione completamente diversa nei file sorgente. In questi casi puoi commentare il parametro offensivo o semplicemente scrivere il parametro.

Esempio:

func(int a, int b)
{
    b;
    foo(a);
}

Questo potrebbe sembrare criptico, così definito una macro come UNUSED. Il modo in cui lo ha fatto MFC è:

#ifdef _DEBUG
#define UNUSED(x)
#else
#define UNUSED(x) x
#endif

In questo modo vedi l'avviso ancora presente nelle build di debug, potrebbe essere utile.


4

Non è sicuro commentare sempre i nomi dei parametri? Altrimenti puoi fare qualcosa del genere

#ifdef _MSC_VER
# define P_(n) n
#else
# define P_(n)
#endif

void ProcessOps::sendToExternalApp(
    QString sAppName, QString sImagePath,
    qreal P_(qrLeft), qreal P_(qrTop), qreal P_(qrWidth), qreal P_(qrHeight))

È un po ' meno brutto.


4
Il fatto che il nome del parametro non sia obbligatorio in C ++ - è in C - è solo per fornire un modo semplice e standard per prevenire l'avvertimento.
AProgrammer,

1
@hacker, non l'ho mai detto. Tendo a evidenziare le differenze tra C e C ++, specialmente quando si trovano in regioni che penseresti siano il sottoinsieme comune ... Solo un'abitudine perché sto lavorando su una base di codice misto.
AProgrammer,

4

Ho visto questo invece del (void)param2modo di mettere a tacere l'avvertimento:

void foo(int param1, int param2)
{
    std::ignore = param2;
    bar(param1);
}

Sembra che questo sia stato aggiunto in C ++ 11


Sembra fare qualcosa, non essere ignorato dopo la compilazione.
GyuHyeon Choi,

3

L'uso di UNREFERENCED_PARAMETER(p)potrebbe funzionare. So che è definito in WinNT.h per sistemi Windows e può essere facilmente definito anche per gcc (se non lo possiede già).

UNREFERENCED PARAMETER(p) è definito come

#define UNREFERENCED_PARAMETER(P)          (P)

in WinNT.h.


2

Usa il flag del compilatore, ad esempio flag per GCC: -Wno-unused-variable


1

È possibile utilizzare __unusedper indicare al compilatore che la variabile potrebbe non essere utilizzata.

- (void)myMethod:(__unused NSObject *)theObject    
{
    // there will be no warning about `theObject`, because you wrote `__unused`

    __unused int theInt = 0;
    // there will be no warning, but you are still able to use `theInt` in the future
}

2
Quale compilatore? Perché __unusednon è C ++ standard, e più precisamente, né è quello che hai pubblicato ... Quello è Objective-C. Quindi questa risposta è davvero utile solo per compilatore / i specifico / i e rende il codice non portatile, e in realtà non è veramente valido poiché il codice utente non è pensato per usare identificatori che iniziano con __l'implementazione, che sono riservati.
underscore_d

1

In C ++ 11, questa è la soluzione che sto usando:

template<typename... Ts> inline void Unreferenced(Ts&&...) {}

int Foo(int bar) 
{
    Unreferenced(bar);
    return 0;
}

int Foo2(int bar1, int bar2) 
{
    Unreferenced(bar1, bar2);
    return 0;
}

Verificato di essere portatile (almeno su moderni msvc, clang e gcc) e non produrre codice extra quando le ottimizzazioni sono abilitate. Senza ottimizzazione, viene eseguita la chiamata di funzione aggiuntiva e i riferimenti ai parametri vengono copiati nello stack, ma non sono coinvolte macro.

Se il codice aggiuntivo è un problema, puoi invece utilizzare questa dichiarazione:

(decltype(Unreferenced(bar1, bar2)))0;

ma a quel punto, una macro offre una migliore leggibilità:

#define UNREFERENCED(...) { (decltype(Unreferenced(__VA_ARGS__)))0; }

1

Funziona bene ma richiede C ++ 11

template <typename ...Args>
void unused(Args&& ...args)
{
  (void)(sizeof...(args));
}

1
Che dire di questo richiede C ++ 14 e non funzionerebbe in C ++ 11? Non vedo niente. Inoltre, è sconsigliato utilizzare ALLCAPSqualsiasi cosa tranne le macro, il che significa renderle brutte e indesiderabili, ma non c'è nulla di male in questo, davvero, tranne che a static_castsarebbe più bello.
underscore_d

0

Ho trovato che la maggior parte delle risposte presentate funziona solo per la variabile locale inutilizzata e causerà un errore di compilazione per la variabile globale statica inutilizzata.

Un'altra macro doveva sopprimere l'avvertimento della variabile globale statica inutilizzata.

template <typename T>
const T* UNUSED_VARIABLE(const T& dummy) { 
    return &dummy;
}
#define UNUSED_GLOBAL_VARIABLE(x) namespace {\
    const auto dummy = UNUSED_VARIABLE(x);\
}

static int a = 0;
UNUSED_GLOBAL_VARIABLE(a);

int main ()
{
    int b = 3;
    UNUSED_VARIABLE(b);
    return 0;
}

Ciò funziona perché non verrà segnalato alcun avviso per la variabile globale non statica nello spazio dei nomi anonimo.

C ++ 11 è richiesto però

 g++  -Wall -O3  -std=c++11 test.cpp

0

Lol! Non credo che ci sia un'altra domanda su SO che rivela meglio tutti gli eretici corrotti dal Caos!

Con tutto il rispetto per C ++ 17 c'è una chiara linea guida nelle Linee guida di base C ++ . AFAIR, nel 2009 questa opzione era disponibile anche oggi. E se qualcuno dice che è considerato un bug in Doxygen, allora c'è un bug in Doxygen


-14

Non vedo il tuo problema con l'avvertimento. Documentalo nell'intestazione metodo / funzione che il compilatore xy emetterà un avviso (corretto) qui, ma che queste variabili sono necessarie per la piattaforma z.

L'avviso è corretto, non è necessario disattivarlo. Non invalida il programma, ma dovrebbe essere documentato, che esiste un motivo.


20
Il problema è che, se hai centinaia o migliaia di tali avvisi, potresti perdere quello che è utile. (Due volte sono stato nella situazione per superare alcune diecimila avvertenze, eliminandone la maggior parte e trovandone alcune davvero utili una volta che hanno accennato a gravi errori.) È sempre bene compilare senza avvisi, se possibile sul livello di avviso più alto.
sbi,

4
In un progetto a cui ho lavorato l'anno scorso ho attivato il livello di avviso più alto e ho ricevuto ~ 10.000 avvisi. Solo poche decine sono state davvero utili. Tra quelli erano nascosti circa una dozzina di bug davvero cattivi, ma ci sono volute diverse settimane per ripulire la base di codice al punto in cui si potevano effettivamente vedere i pochi gravi. Se il livello di avviso fosse costantemente aumentato e la base di codice fosse stata mantenuta priva di avvisi, quegli errori non si sarebbero mai insinuati nel codice.
sbi,

1
scusate - ma fare l'analisi del codice statico (usando qualsiasi strumento disponibile, anche se è solo il compilatore) in ritardo nel progetto è un po 'come programmare l'intero programma e quando finite, premete compilate e sperate di non avere errori.
Tobias Langner,

2
@Richard: ho lavorato su progetti con migliaia di file sorgente. Un piccolo avvertimento qua e là, anche ben documentato, si aggiunge rapidamente. Anche se hai una dozzina di avvisi che lampeggiano durante una build (anziché centinaia o migliaia), doverli cercare individualmente per vedere se sono nuovi o documentati richiede troppo tempo e, alla fine, ha vinto ' essere fatto. Pertanto: compilare il livello di avviso più alto possibile con zero avvisi. Ogni avvertimento che viene emesso verrà immediatamente notato, guardato e riparato o sorpreso.
sbi,

2
@sbi: il turining sul livello di avviso più alto per il tuo compilatore è una forma di analisi del codice statico. L'analisi del codice statico è solo leggere il codice senza eseguirlo e dedurre informazioni da esso. Questo è esattamente ciò che fa il compilatore quando controlla le sue regole per gli avvisi.
Tobias Langner,
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.