Como desativar os avisos do GCC para algumas linhas de código

220

No Visual C ++, é possível usar #pragma warning (disable: ...). Também descobri que no GCC você pode substituir os sinalizadores por compilador de arquivo . Como posso fazer isso para "próxima linha" ou com semântica push / pop em torno de áreas de código usando o GCC?

Matt Joiner
fonte
1
possível duplicação de desativar avisos específicos no gcc - Opa, na verdade, essa pergunta em si é um dupe (mas não está fechado). Acontece que esse foi o que apareceu em "Relacionados". De qualquer forma, isso foi solicitado e respondido várias vezes no SO.
Tyler McHenry
1
@ paxdiablo: Estou fazendo o contrário. Aumentei muito o nível de aviso e quero esmagar os avisos linha por linha que eu verifiquei estarem bem.
Matt Joiner
4
@ Tyler McHenry: Se você checar com mais cuidado, poderá observar que a pergunta vinculada contém uma solução por arquivo, precisamente a que mencionei na minha própria pergunta como insatisfatória (até roubei o link).
Matt Joiner
6
@paxdiablo, os compiladores fornecem falsos positivos, às vezes você deseja compilar com -Werror, mas não possui esses falsos positivos para bloquear uma compilação. desabilitar casos específicos e comentar o porquê - faz sentido em alguns casos. Também há outros casos em que isso pode ser útil - como código de geração automática que produz avisos inofensivos que não são tão fáceis de inserir e alterar (desde que o código é gerado), embora nesse caso seja mais provável que a desativação por arquivo a solução.
ideasman42

Respostas:

221

Parece que isso pode ser feito . Não consigo determinar a versão do GCC que foi adicionada, mas ocorreu antes de junho de 2010.

Aqui está um exemplo:

#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
fonte
14
um pushe dois pops - pode ser outro pushno início está faltando?
abyss.7
37
"#pragma push de diagnóstico do GCC #pragma pop de diagnóstico do GCC Faz com que o GCC se lembre do estado dos diagnósticos a cada push e restaure nesse ponto em cada pop. Se um pop não tiver push correspondente, as opções da linha de comando serão restauradas. " - do manual do GCC: gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html
bobpaul
11
Para referência, versão gcc 4.4.3 suportes erro / aviso / ignorado, mas não push / pop
frankster
12
A primeira versão do GCC que apresentou push / pop de diagnóstico é o GCC 4.6.4 . Eu determinei isso olhando para a seção Diagnóstico-Pragmas.html # Diagnostic-Pragmas para cada versão GCC na documentação do GCC
Bitek
5
É uma pena que isso não funcione na prática. Em alguns casos, produz mais avisos. Ou talvez, mais corretamente, ele não funcione na prática para o GCC 4.7 a 5.1. Veja, por exemplo, o GCC não respeita o 'diagnóstico pragma do GCC' para silenciar avisos .
JWW
108

Para compensar tudo, este é um exemplo de desativar temporariamente um aviso:

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

Você pode verificar a documentação do GCC sobre pragmas de diagnóstico para obter mais detalhes.

Ian Pilcher
fonte
2
Deve funcionar, mas o meu gcc-4.9simplesmente ignora essa linha completamente.
Aleksei Petrenko
31

TL; DR : Se funcionar, evite ou use especificadores como o __attribute__contrário _Pragma.

Esta é uma versão curta do meu artigo de blog Suprimindo avisos no GCC e no Clang .

Considere o seguinte Makefile

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

.PHONY: all
all: puts

para criar o seguinte puts.ccódigo fonte

#include <stdio.h>

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

Ele não será compilado porque argcnão está sendo usado e as configurações são graves ( -W -Wall -pedantic -Werror).

Existem 5 coisas que você pode fazer:

  • Melhore o código fonte, se possível
  • Use um especificador de declaração, como __attribute__
  • Usar _Pragma
  • Usar #pragma
  • Use uma opção de linha de comando.

Melhorando a fonte

A primeira tentativa deve verificar se o código fonte pode ser aprimorado para se livrar do aviso. Nesse caso, não queremos alterar o algoritmo apenas por causa disso, pois argcé redundante com !*argv( NULLapós o último elemento).

Usando um especificador de declaração, como __attribute__

#include <stdio.h>

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

Se você tiver sorte, o padrão fornece um especificador para a sua situação, como _Noreturn.

__attribute__é uma extensão proprietária do GCC (suportada pelo Clang e outros compiladores armcc) e não será compreendida por muitos outros compiladores. Coloque __attribute__((unused))dentro de uma macro se você quiser código portátil.

_Pragma operador

_Pragmapode ser usado como uma alternativa para #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")

A principal vantagem do _Pragmaoperador é que você pode colocá-lo dentro de macros, o que não é possível com a #pragmadiretiva.

Desvantagem: é quase uma bomba nuclear tática, pois funciona com base em linhas, em vez de em declarações.

O _Pragmaoperador foi introduzido no C99.

#pragma directiva.

Poderíamos alterar o código fonte para suprimir o aviso para uma região de código, normalmente uma função inteira:

#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

Desvantagem: é quase uma bomba nuclear tática, pois funciona com base em linhas, em vez de em declarações.

Observe que uma sintaxe semelhante existe no clang .

Suprimindo o aviso na linha de comandos para um único arquivo

Poderíamos adicionar a seguinte linha ao Makefilepara suprimir o aviso especificamente para o put:

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

.PHONY: all
all: puts

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

Provavelmente, não é o que você deseja no seu caso específico, mas pode ajudar outras leituras que estão em situações semelhantes.

Christian Hujer
fonte
2
re: improving the sourcetambém funcionaria para mudar a declaração de main para int main(int, const char* argv[]) { ... }não dando um nome ao argumento, você diz ao compilador que ele não será utilizado.
Jesse Chisholm
1
@JesseChisholm omitir o nome do parâmetro na definição da função não é possível. Consulte 6.9.1 Definições de funções da ISO / IEC9899, ​​§5 "Se o declarador incluir uma lista de tipos de parâmetros, a declaração de cada parâmetro deverá incluir um identificador […]" E corretamente, para que o código seja rejeitado gcce também clang.
Christian Hujer
1
Outro padrão é apenas fazer uma conversão da variável para anular. De fato, vi em um projeto a seguinte macro: #define UNUSED(x) ((void)x)usada para silenciar avisos. Eu acho que foi no ReactOS?
Paul Stelian
1
Acho que você não precisa da barra invertida depois disso, não? _Pragma("GCC diagnostic pop") \ deveria ser apenas _Pragma("GCC diagnostic pop")eu acho.
Gabriel Staples
1
@GabrielStaples Está correto, obrigado por perceber que atualizei a resposta.
Christian Hujer 18/03
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

Isso deve fazer o truque para gcc, clang e msvc

Pode ser chamado com, por exemplo:

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

consulte 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 para obter mais detalhes

Você precisa pelo menos da versão 4.02 para usar esse tipo de pragmas para o gcc, não tenho certeza sobre o msvc e não comenta as versões.

Parece que o manuseio do pragma push pop para o gcc está um pouco quebrado. Se você ativar o aviso novamente, ainda receberá o aviso para o bloco que estava dentro do bloco DISABLE_WARNING / ENABLE_WARNING. Para algumas versões do gcc, funciona, para outras, não.

Martin Gerhardy
fonte
3
Você é o verdadeiro MVP
zeboidlund
19
#pragma GCC diagnostic ignored "-Wformat"

Substitua "-Formato" pelo nome do seu sinalizador de aviso.

No AFAIK, não há como usar a semântica push / pop para esta opção.

Joe D
fonte
4
É uma pena que isso não funcione na prática. Em alguns casos, produz mais avisos. Ou talvez, mais corretamente, ele não funcione na prática para o GCC 4.7 a 5.1. Veja, por exemplo, o GCC não respeita o 'diagnóstico pragma do GCC' para silenciar avisos .
JWW
6

Eu tive o mesmo problema com bibliotecas externas como cabeçalhos ROS. Eu gosto de usar as seguintes opções no CMakeLists.txt para uma compilação mais rigorosa:

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

Entretanto, fazer isso causa todos os tipos de erros pedantes nas bibliotecas incluídas externamente. A solução é desativar todos os avisos pedantes antes de incluir bibliotecas externas e reativar assim:

//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
fonte
2
Isso não deveria ser melhor tratado com os diretórios de sistema do gcc ?
Red XIII
@RedXIII - sim, essa é uma opção se você pode fazer uma lista desses diretórios e especificar na linha de comando do gcc. No entanto, muitas vezes o compilador é chamado profundamente no pipeline ou você não tem muito controle sobre como outra pessoa deve compilar seu código. Nos casos acima, provavelmente é uma solução melhor.
Shital Shah 02/12/19
5

Eu sei que a pergunta é sobre o GCC, mas para pessoas que procuram como fazer isso em outros e / ou vários compiladores ...

TL; DR

Você pode dar uma olhada no Hedley , que é um cabeçalho C / C ++ de domínio público que escrevi, que faz muitas dessas coisas para você. Vou colocar uma seção rápida sobre como usar o Hedley para tudo isso no final deste post.

Desativando o aviso

#pragma warning (disable: …) possui equivalentes na maioria dos compiladores:

  • MSVC: #pragma warning(disable:4996)
  • GCC: #pragma GCC diagnostic ignored "-W…"onde as reticências são o nome do aviso; por exemplo , #pragma GCC diagnostic ignored "-Wdeprecated-declarations.
  • clang: #pragma clang diagnostic ignored "-W…". A sintaxe é basicamente a mesma que a do GCC, e muitos dos nomes de aviso são os mesmos (embora muitos não sejam).
  • Compilador Intel C: use a sintaxe MSVC, mas lembre-se de que os números de aviso são totalmente diferentes. Exemplo: #pragma warning(disable:1478 1786).
  • IGP: Existe um diag_suppresspragma:#pragma diag_suppress 1215,1444
  • TI: Existe uma diag_suppress pragma com a mesma sintaxe (mas com números de aviso diferentes!) Da IGP:pragma diag_suppress 1291,1718
  • Oracle Developer Studio (suncc): existe um error_messages pragma. Irritantemente, os avisos são diferentes para os compiladores C e C ++. Ambos desabilitam basicamente os mesmos avisos:
    • C: #pragma error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)
    • C ++: #pragma error_messages(off,symdeprecated,symdeprecated2)
  • IAR: também usa diag_suppress como IGP e TI, mas a sintaxe é diferente. Alguns dos números de aviso são os mesmos, mas eu outros divergimos:#pragma diag_suppress=Pe1444,Pe1215
  • Pelles C: semelhante ao MSVC, embora novamente os números sejam diferentes #pragma warn(disable:2241)

Para a maioria dos compiladores, geralmente é uma boa ideia verificar a versão do compilador antes de tentar desabilitá-la; caso contrário, você acabará acionando outro aviso. Por exemplo, o GCC 7 adicionou suporte ao -Wimplicit-fallthroughaviso, portanto, se você se importa com o GCC antes do 7, deve fazer algo como

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

Para clang e compiladores baseados em clang, como nas versões mais recentes do XL C / C ++ e armclang, você pode verificar se o compilador conhece um aviso específico usando a __has_warning()macro.

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

Claro que você também precisa verificar se a __has_warning()macro existe:

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

Você pode ficar tentado a fazer algo como

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

Então você pode usar __has_warningum pouco mais facilmente. Clang até sugere algo semelhante para a __has_builtin()macro em seu manual. Não faça isso . Outro código pode procurar __has_warninge recorrer à verificação de versões do compilador, se não existir, e se você definir, __has_warningquebrará o código. A maneira correta de fazer isso é criar uma macro no seu espaço para nome. Por exemplo:

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

Então você pode fazer coisas como

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

Empurrando e estourando

Muitos compiladores também oferecem suporte a uma maneira de enviar e enviar avisos para uma pilha. Por exemplo, isso desativará um aviso no GCC para uma linha de código e retornará ao estado anterior:

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

É claro que não há muito acordo entre os compiladores sobre a sintaxe:

  • GCC 4.6+: #pragma GCC diagnostic push/#pragma GCC diagnostic pop
  • clang: #pragma clang diagnostic push/#pragma diagnostic pop
  • Intel 13+ (e provavelmente anterior): #pragma warning(push)/#pragma warning(pop)
  • MSVC 15+ (VS 9.0 / 2008): #pragma warning(push)/#pragma warning(pop)
  • BRAÇO 5.6+: #pragma push/#pragma pop
  • TI 8.1+: #pragma diag_push/#pragma diag_pop
  • Pelles C 2.90+ (e provavelmente anterior): #pragma warning(push)/#pragma warning(pop)

Se a memória serve, para algumas versões muito antigas do GCC (como 3.x, IIRC), os pragmas push / pop precisavam estar fora da função.

Escondendo os detalhes sangrentos

Para a maioria dos compiladores, é possível ocultar a lógica por trás das macros usando _Pragma, introduzida no C99. Mesmo no modo não C99, a maioria dos compiladores suporta _Pragma; a grande exceção é o MSVC, que possui sua própria __pragmapalavra-chave com uma sintaxe diferente. O padrão _Pragmausa uma string, a versão da Microsoft não:

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

É aproximadamente equivalente, uma vez pré-processado, a

#pragma foo

Isso nos permite criar macros para escrever código como

MY_DIAGNOSTIC_PUSH
MY_DIAGNOSTIC_DISABLE_DEPRECATED
call_deprecated_function();
MY_DIAGNOSTIC_POP

E esconda todas as verificações feias das versões nas definições de macro.

O caminho mais fácil: Hedley

Agora que você entende a mecânica de como fazer coisas assim de maneira portável, mantendo seu código limpo, entende o que um dos meus projetos, Hedley faz. Em vez de vasculhar toneladas de documentação e / ou instalar o maior número possível de compiladores para testar, basta incluir o Hedley (é um cabeçalho C / C ++ de domínio público) e pronto. Por exemplo:

#include "hedley.h"

HEDLEY_DIAGNOSTIC_PUSH
HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
call_deprecated();
HEDLEY_DIAGNOSTIC_POP

Desabilitará o aviso sobre a chamada de uma função obsoleta no GCC, clang, ICC, PGI, MSVC, TI, IAR, ODS, Pelles e possivelmente outras (provavelmente não me incomodarei em atualizar esta resposta ao atualizar o Hedley). E, nos compiladores que não são conhecidos por funcionar, as macros serão pré-processadas para nada, portanto, seu código continuará funcionando com qualquer compilador. É claro que esse HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATEDnão é o único aviso que Hedley conhece, nem os avisos desabilitadores que Hedley pode fazer, mas espero que você entenda.

nemequ
fonte
3

Em vez de silenciar os avisos, o estilo gcc geralmente usa construções C padrão ou a __attribute__extensão para informar ao compilador mais sobre sua intenção. Por exemplo, o aviso sobre a atribuição usada como condição é suprimido colocando a atribuição entre parênteses, ou seja, em if ((p=malloc(cnt)))vez de if (p=malloc(cnt)). Os avisos sobre argumentos de funções não utilizadas podem ser suprimidos por alguns itens estranhos dos quais __attribute__nunca me lembro, ou por auto-designações, etc. Mas geralmente prefiro desabilitar globalmente qualquer opção de aviso que gere avisos para coisas que ocorrerão no código correto.

R .. GitHub PARE DE AJUDAR O GELO
fonte
2
Talvez sim. Minha intenção não é provar nenhum padrão geral de caso, mas uma observação sobre o que parece ser a filosofia do gcc sobre a supressão de avisos.
R .. GitHub Pare de ajudar o gelo
O compilador se comporta de maneira diferente com avisos / par / t com parênteses adicionados?!?! ?? !!!! UAU! Isso é inesperado.
Jason S
1
@ Jason, o parens não altera o comportamento do compilador por meio de avisos, o que faz é alterar a semântica da declaração. As parênteses extras fazem com que o compilador termine a atribuição e mantenha seu valor final como uma expressão, que não merece aviso. Se você quiser clareza, pode dizer if ((p=malloc(cnt)) != NULL) ...que é isso que o compilador está fazendo nos bastidores.
Jesse Chisholm
@JesseChisholm: Eu não acho que sua explicação seja precisa.
R .. GitHub Pare de ajudar o gelo
3

Para quem encontrou esta página procurando uma maneira de fazer isso no IAR, tente o seguinte:

#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

Consulte http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0472m/chr1359124244797.html para obter referência.

Keron
fonte