Como melhor silenciar um aviso sobre variáveis ​​não utilizadas?


237

Eu tenho um aplicativo de plataforma cruzada e em algumas de minhas funções nem todos os valores passados ​​para as funções são utilizados. Por isso, recebo um aviso do GCC informando que existem variáveis ​​não utilizadas.

Qual seria a melhor maneira de codificar o aviso?

Um #ifdef em torno da função?

#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
{

Isso é tão feio, mas parece da maneira que o compilador prefere.

Ou atribuo zero à variável no final da função? (que eu odeio porque está alterando algo no fluxo do programa para silenciar um aviso do compilador).

Existe uma maneira correta?


7
Acabei de perceber que você fez uma pergunta semelhante em novembro passado. É por isso que parece familiar! ;) stackoverflow.com/questions/308277/…
Alex B

9
Por que não apenas comentá-los para os dois compiladores? Se o argumento é não utilizado em um, ele provavelmente vai ser utilizada por outro ...
Roger Lipscombe

12
você deve saber que o Qt tem uma Q_UNUSEDmacro apenas para isso. Confira na documentação.
Evan Teran

1
A solução C também funciona bem em C ++: stackoverflow.com/a/3599170/1904815 #
31514 JonnyJD

-Wno-unused-parâmetro também pode ser uma opção se você pode ter bandeiras compilação específica do compilador
Código Abominator

Respostas:


327

Você pode colocá-lo na (void)var;expressão " " (não faz nada) para que um compilador veja que ele é usado. Isso é portátil entre compiladores.

Por exemplo

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

Ou,

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

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

22
+1 - ainda documentaria por que você não usa a variável, mesmo que ela esteja lá.
Tobias Langner 29/09/09

18
É assim que Q_UNUSEDé implementado em princípio.
Dmitry Volosnykh

11
@Cameron, você pode simplesmente omitir o nome do parâmetro em C ++. Se estiver modelado, não será usado em C, portanto, você não precisa do truque do elenco para o vazio.
Alex B

13
#define UNUSED(expr) (void)(expr)deve funcionar também (sem o tempo de espera).
JonnyJD

7
Gostaria de saber como fazer isso para um modelo variadic. Em template<typename... Args> void f(const Args&... args)Eu não posso escrever (void)args;ou (void)args...;porque ambos são erros de sintaxe.
Panzi

101

No GCC e no Clang, você pode usar a __attribute__((unused))diretiva de pré - processador para atingir seu objetivo.
Por exemplo:

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

1
Esta é a melhor solução para funções de retorno de chamada.
Sonic Atom

1
Também suportado por clang: clang.llvm.org/docs/…
Alexander


39

Sua solução atual é a melhor - comente o nome do parâmetro se você não o usar. Isso se aplica a todos os compiladores, portanto você não precisa usar o pré-processador para fazê-lo especialmente no GCC.


7
Apenas para reforçar esta resposta - você não precisa do #ifdef, apenas comente os nomes dos parâmetros não utilizados.
quamrana 28/09/09

4
Eu tenho um caso em que o parâmetro faz parte de um retorno de chamada e comentá-lo interrompe a compilação (por isso não sei por que o g++aviso está sendo feito). Nesse caso, o que você recomendaria?
de Drew Noakes

1
Imagine um método virtual embutido com parâmetros não utilizados / * comentado * /, o cliente da interface não verá o nome do parâmetro durante o preenchimento automático na maioria dos IDEs. Nesse caso, a solução UNUSED () é mais conveniente, embora menos limpa.
Cbuchart 17/07/2014

Eu acho mais simples é melhor, comentando é muito clara
Fievel

26

Atualização C ++ 17

No C ++ 17, obtemos o atributo [[maybe_unused]], coberto em [dcl.attr.unused]

O token de atributo maybe_unused indica que um nome ou entidade possivelmente não é utilizado intencionalmente. Ele deve aparecer no máximo uma vez em cada lista de atributos e nenhuma cláusula de argumento-argumento deve estar presente. ...

Exemplo:

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

As implementações não devem avisar que b não está sendo usado, se NDEBUG está ou não definido. Exemplo final]

Para o seguinte exemplo:

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

Clang e gcc geram um diagnóstico usando -Wall -Wextra para bar e unused_bool ( Veja ao vivo ).

Ao adicionar [[maybe_unused]] silencia o diagnóstico:

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

veja ao vivo .

Antes do C ++ 17

No C ++ 11, uma forma alternativa da UNUSEDmacro pode ser formada usando uma expressão lambda ( via Ben Deane ) com uma captura da variável não utilizada:

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

A chamada imediata da expressão lambda deve ser otimizada, dado o seguinte exemplo:

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

podemos ver em godbolt que a chamada está otimizada:

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

5
Então você menciona C ++ 11 e consegue apresentar uma macro ?! Ai! Talvez o uso de uma função seja mais limpo? template <class T> inline void NOTUSED( T const & result ) { static_cast<void>(result); }Você também pode usar um lambda na função, suponho.
Alexis Wilke

Godbolt é um grande recurso
yano

5
[&x]{}()realmente não silencia o aviso, mas passa o aviso da função de chamada para o lambda. Vai levar tempo até que os compiladores identifiquem isso como um aviso, mas o clang-tidy já reclama de uma variável não utilizada na lista de capturas.
NVxx 17/04

25

Uma maneira ainda mais limpa é apenas comentar os nomes das variáveis:

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

8
Isso não é bom se você tiver doxygen e quiser documentar os parâmetros.
Alexis Wilke

18
@AlexisWilke: Isso se qualificaria como um bug no doxygen, IMO
6502

3
Você pode # definir YOUR_PROJECT_UNUSED (argname) condicionalmente em #ifdef DOXYGEN para que o doxygen possa ver o nome e o compilador real não, via int main (int YOUR_PROJECT_UNUSED (argc), ...). Não é fabuloso, mas funciona.
Mabraham

Acho muito doloroso comentar um bloco de código com muitos desses comentários aninhados. (o compilador reclama de cada um).
Jeff McClintock

@JeffMcClintock apenas use comentários de linha única. A maioria dos editores decentes suporta a edição vertical de blocos (por exemplo, [Ctrl] + [V] no Vim). Caso contrário, use #if 0 / #endifcomentários em bloco.
Ruslan

24

Um colega de trabalho acabou de me apontar para esta bela macro aqui

Para facilitar, incluirei a macro abaixo.

#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
"agradável" "macro" "c ++" - escolha 2.
Jeff McClintock

23

não sinaliza esses avisos por padrão. Esse aviso deve ter sido ativado explicitamente passando -Wunused-parameterpara o compilador ou implicitamente passando -Wall -Wextra(ou possivelmente alguma outra combinação de sinalizadores).

Os avisos de parâmetro não utilizados podem ser simplesmente suprimidos, passando -Wno-unused-parameterpara o compilador, mas observe que esse sinalizador de desativação deve vir após qualquer sinalizador de ativação possível para esse aviso na linha de comando do compilador, para que ele entre em vigor.


2
Mesmo assim, essa talvez não seja a melhor resposta para a pergunta (porque a questão era como evitar o aviso, não como desativá-lo), essa resposta pode ser que as pessoas vindas do google (como eu) estavam procurando ("como para desativar este aviso "). Então, eu dou +1, obrigado pela sua resposta!
mozzbozz

13

maneira sem macro e portátil de declarar um ou mais parâmetros como não utilizados:

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

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

Muito bom, mas observe que isso requer C ++ 11 (ou mais recente, é claro).
Paul R

Votei esta resposta para baixo porque não gostaria de sacrificar o tempo de compilação (usando modelos) apenas para me livrar do aviso.
Konrad Kleine

@KonradKleine: Quanto tempo de compilação isso poderia consumir? Testando no meu computador, posso executar milhares dessas chamadas não utilizadas () em um décimo da segunda.
Daniel McLaury

@DanielMcLaury esse foi apenas o meu palpite e eu não fiz nenhum experimento.
Konrad Kleine

8

O uso de diretivas de pré-processador é considerado ruim na maioria das vezes. Idealmente, você deseja evitá-los como a praga. Lembre-se de que é fácil fazer o compilador entender seu código, permitindo que outros programadores entendam seu código muito mais difícil. Algumas dezenas de casos como esse aqui e ali dificultam a leitura para você mais tarde ou para outras pessoas agora.

Uma maneira pode ser reunir seus parâmetros em algum tipo de classe de argumento. Você poderia usar apenas um subconjunto das variáveis ​​(equivalente a atribuir 0 realmente) ou ter diferentes especializações dessa classe de argumentos para cada plataforma. No entanto, isso pode não valer a pena, você precisa analisar se isso se encaixaria.

Se você conseguir ler modelos impossíveis, poderá encontrar dicas avançadas no livro "Excepcional C ++". Se as pessoas que leram o seu código pudessem incluir suas habilidades abrangendo as coisas loucas ensinadas nesse livro, você teria um código bonito que também pode ser facilmente lido. O compilador também estaria bem ciente do que você está fazendo (em vez de ocultar tudo com o pré-processamento)


5
"O uso de diretivas de pré-processador é considerado maligno na maioria das vezes." Realmente? Por quem?
Graeme Perrow

12
Por qualquer pessoa que se preocupe com o escopo, seja capaz de depurar corretamente ou com sua sanidade.
Bill de Bill

2
@ Graeme, parece inocente quando vemos apenas quatro linhas, mas espalhar ao redor causa dor de cabeça. O #ifdef basicamente permite que você coloque várias versões de um código-fonte dos quais o compilador verá apenas um. Como Bill menciona, também torna mais difícil a depuração. Eu li sobre a maldade das diretrizes do pré-processador em diversos livros e blogs, além de ter experimentado isso sozinho. Claro, tudo é relativo. Às vezes, as diretivas de pré-processador simplesmente fazem sentido, porque qualquer outra coisa teria consequências piores, e meu argumento aqui é apenas que isso deve ser evitado sempre que possível.
Ben Dadsetan 28/09/09

1
O uso excessivo é ruim, mas eu chamaria #define UNUSED(expr) (void)(expr)apropriado.
JonnyJD

7

Primeiro, o aviso é gerado pela definição de variável no arquivo de origem e não no arquivo de cabeçalho. O cabeçalho pode permanecer intocado e deve, pois você pode estar usando algo como doxygen para gerar a documentação da API.

Assumirei que você tenha uma implementação completamente diferente nos arquivos de origem. Nesses casos, você pode comentar o parâmetro incorreto ou apenas escrever o parâmetro.

Exemplo:

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

Isso pode parecer enigmático, então definiu uma macro como NÃO UTILIZADA. A maneira como o MFC fez isso é:

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

Assim você vê o aviso ainda nas compilações de depuração, pode ser útil.


4

Não é seguro comentar sempre os nomes dos parâmetros? Se não for, você pode fazer algo como

#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))

É um pouco menos feio.


4
O fato de o nome do parâmetro não ser obrigatório em C ++ - é em C - serve apenas para fornecer uma maneira padrão e fácil de impedir o aviso.
AProgrammer 28/09/09

1
@ hacker, nunca disse que era. Costumo apontar diferenças entre C e C ++, especialmente quando estão em regiões que você acha que é o subconjunto comum ... Apenas um hábito, porque estou trabalhando em uma base de código mista.
AProgrammer 28/09/09

4

Eu vi isso em vez da (void)param2maneira de silenciar o aviso:

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

Parece que isso foi adicionado no C ++ 11


Parece estar fazendo algo, não sendo ignorado após a compilação.
GyuHyeon Choi 23/02

3

Usando um UNREFERENCED_PARAMETER(p)poderia funcionar. Eu sei que ele está definido no WinNT.h para sistemas Windows e também pode ser facilmente definido para o gcc (se ainda não o tiver).

UNREFERENCED PARAMETER(p) é definido como

#define UNREFERENCED_PARAMETER(P)          (P)

no WinNT.h.


2

Use a bandeira do compilador, por exemplo, bandeira para o GCC: -Wno-unused-variable


1

Você pode usar __unusedpara informar ao compilador que a variável não pode ser usada.

- (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
Qual compilador? Porque __unusednão é C ++ padrão, e mais ao ponto, nem o que você postou ... Isso é Objective-C. Portanto, essa resposta é realmente útil apenas para compilador (es) específico (s), e torna o código não portátil e, na verdade, não é válido, pois o código do usuário não se destina a usar identificadores iniciados por __, reservados para a implementação.
underscore_d

1

No C ++ 11, esta é a solução que estou 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;
}

Verificado como portátil (pelo menos no msvc moderno, clang e gcc) e não produzindo código extra quando as otimizações estão ativadas. Sem otimização, a chamada de função extra é executada e as referências aos parâmetros são copiadas para a pilha, mas não há macros envolvidas.

Se o código extra for um problema, você poderá usar esta declaração:

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

mas, nesse ponto, uma macro fornece melhor legibilidade:

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

1

Isso funciona bem, mas requer C ++ 11

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

1
Que tal isso requer C ++ 14 e não funcionaria em C ++ 11? Eu não consigo ver nada. Além disso, é desencorajado o uso ALLCAPSde qualquer coisa, exceto macros, que é para torná-las feias e indesejáveis, mas não há nada de ruim nisso, na verdade, exceto que um static_castseria melhor.
Underscore_d

0

Descobri que a maioria das respostas apresentadas funciona apenas para variáveis ​​locais não utilizadas e causará erro de compilação para variável global estática não utilizada.

Outra macro necessária para suprimir o aviso de variável global estática não utilizada.

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;
}

Isso funciona porque nenhum aviso será relatado para variável global não estática no espaço para nome anônimo.

C ++ 11 é necessário

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

0

Ri muito! Eu não acho que exista outra pergunta sobre SO que revele todos os hereges corrompidos pelo Caos melhor que este!

Com todo o respeito ao C ++ 17, há uma diretriz clara nas Diretrizes Principais do C ++ . AFAIR, em 2009 essa opção estava disponível também hoje. E se alguém diz que é considerado um bug no Doxygen, existe um bug no Doxygen


-14

Não vejo seu problema com o aviso. Documente no cabeçalho do método / função que o compilador xy emitirá um aviso (correto) aqui, mas que essas variáveis ​​são necessárias para a plataforma z.

O aviso está correto, não há necessidade de desligá-lo. Ele não invalida o programa - mas deve ser documentado, que existe um motivo.


20
O problema é que, se você tiver centenas ou milhares desses avisos, poderá perder o que é útil. (Duas vezes eu estava na situação de percorrer vários milhares de avisos, eliminando a maioria e encontrando alguns realmente úteis uma vez que sugeriam erros graves.) É sempre bom compilar sem avisos, se possível no nível de aviso mais alto.
sbi 28/09/09

4
Em um projeto em que trabalhei no ano passado, ativei o nível mais alto de aviso e recebi ~ 10.000 avisos. Apenas algumas dezenas foram realmente úteis. Entre eles estavam escondidos cerca de uma dúzia de bugs realmente desagradáveis, mas levou várias semanas para limpar a base de código até o ponto em que era possível ver os poucos sérios. Se o nível de aviso tivesse aumentado o tempo todo e a base de código tivesse sido mantida sem aviso, esses erros nunca teriam entrado no código.
sbi 29/09/09

1
desculpe - mas fazer a análise de código estático (usando qualquer ferramenta que você tenha disponível, mesmo que seja apenas o compilador) no final do projeto é um pouco como programar todo o programa e, quando terminar, pressione compilar e espero que não haja erros.
Tobias Langner 29/09/09

2
@ Richard: Eu trabalhei em projetos com milhares de arquivos de origem. Um pequeno aviso aqui e ali, mesmo os bem documentados, acrescenta-se rapidamente. Mesmo que você tenha apenas dezenas de avisos piscando durante uma compilação (em vez de centenas ou milhares), ter que procurá-los individualmente para ver se são novos ou documentados é muito demorado e, no final, vence ' não seja feito. Para isso: Compile no nível de aviso mais alto possível com zero avisos. Todo aviso que surgir será notado imediatamente, analisado e corrigido ou suprimido.
Sbi 29/09/09

2
@sbi: encontrar o nível de aviso mais alto para o seu compilador é uma forma de análise estática de código. A análise de código estático é apenas ler o código sem executá-lo e deduzir informações dele. É exatamente isso que o compilador faz quando verifica suas regras quanto a avisos.
Tobias Langner 30/09/09
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.