Por contexto, sou desenvolvedor de Clang trabalhando no Google. No Google, lançamos o diagnóstico de Clang para (essencialmente) todos os nossos desenvolvedores de C ++ e tratamos os avisos de Clang como erros também. Como desenvolvedor do Clang e um dos maiores usuários dos diagnósticos do Clang, tentarei lançar alguma luz sobre esses sinalizadores e como eles podem ser usados. Observe que tudo o que estou descrevendo é genericamente aplicável ao Clang e não específico ao C, C ++ ou Objective-C.
TL; DR Versão: Por favor, use -Wall
e -Werror
, no mínimo, em qualquer novo código que você está desenvolvendo. Nós (os desenvolvedores do compilador) adicionamos avisos aqui por boas razões: eles encontram bugs. Se você encontrar um aviso que detecta bugs para você, ative-o também. Tente -Wextra
um monte de bons candidatos aqui. Se um deles for muito barulhento para você usar com lucro, registre um bug . Se você escrever um código que contenha um bug "óbvio", mas o compilador não o alertou, registre um bug.
Agora para a versão longa. Primeiro, alguns antecedentes sobre grupos de sinalizadores de aviso. Existem muitos "agrupamentos" de avisos em Clang (e até certo ponto no GCC). Alguns que são relevantes para esta discussão:
- Ativado por padrão: esses avisos estão sempre ativados, a menos que você os desative explicitamente.
-Wall
: São avisos de que os desenvolvedores têm alta confiança em seu valor e em uma baixa taxa de falso positivo.
-Wextra
: Esses avisos são considerados valiosos e sólidos (ou seja, não são de buggy), mas podem ter altas taxas de falso-positivos ou objeções filosóficas comuns.
-Weverything
: Este é um grupo insano que literalmente habilita todos os
avisos no Clang. Não use isso no seu código. Destina-se estritamente aos desenvolvedores do Clang ou para explorar quais avisos existem .
Existem dois critérios principais mencionados acima que orientam para onde os avisos vão em Clang, e vamos esclarecer o que eles realmente significam. O primeiro é o valor potencial
de uma ocorrência específica do aviso. Esse é o benefício esperado para o usuário (desenvolvedor) quando o aviso é acionado e
identifica corretamente um problema com o código.
O segundo critério é a ideia de relatórios falso-positivos . São situações em que o aviso é acionado no código, mas o problema potencial que está sendo citado não ocorre de fato devido ao contexto ou a alguma outra restrição do programa. O código avisado está realmente se comportando corretamente. Isso é especialmente ruim quando o aviso nunca foi planejado para disparar nesse padrão de código. Em vez disso, é uma deficiência na implementação do aviso que o aciona ali.
Para avisos de Clang, é necessário que o valor seja em termos de correção , não em termos de estilo, sabor ou convenções de codificação. Isso limita o conjunto de avisos disponíveis, impedindo avisos frequentemente solicitados, como aviso sempre que {}
s não são usados no corpo de uma if
declaração. Clang também é muito intolerante a falsos positivos . Diferente da maioria dos outros compiladores, ele usará uma variedade incrível de fontes de informação para remover falsos positivos, incluindo a ortografia exata da construção, presença ou ausência de '()', projeções ou mesmo macros de pré-processador!
Agora vamos dar alguns exemplos de avisos do Clang no mundo real e ver como eles são categorizados. Primeiro, um aviso padrão:
% nl x.cc
1 class C { const int x; };
% clang -fsyntax-only x.cc
x.cc:1:7: warning: class 'C' does not declare any constructor to initialize its non-modifiable members
class C { const int x; };
^
x.cc:1:21: note: const member 'x' will never be initialized
class C { const int x; };
^
1 warning generated.
Aqui, nenhum sinalizador foi necessário para receber esse aviso. A lógica é que esse código nunca é realmente correto, fornecendo um valor alto ao aviso , e o aviso é acionado apenas no código que Clang pode provar que cai nesse intervalo, fornecendo a ele uma taxa de falso positivo zero .
% nl x2.cc
1 int f(int x_) {
2 int x = x;
3 return x;
4 }
% clang -fsyntax-only -Wall x2.cc
x2.cc:2:11: warning: variable 'x' is uninitialized when used within its own initialization [-Wuninitialized]
int x = x;
~ ^
1 warning generated.
Clang requer o -Wall
sinalizador para este aviso. A razão é que existe uma quantidade não trivial de código por aí que usou (para o bem ou para o mal) o padrão de código que estamos alertando para produzir intencionalmente um valor não inicializado. Filosoficamente, não vejo sentido nisso, mas muitos outros discordam e a realidade dessa diferença de opinião é o que impulsiona o alerta
-Wall
. Ele ainda possui um valor muito alto e uma taxa de falso-positivo muito baixa
, mas em algumas bases de código não é inicial.
% nl x3.cc
1 void g(int x);
2 void f(int arr[], unsigned int size) {
3 for (int i = 0; i < size; ++i)
4 g(arr[i]);
5 }
% clang -fsyntax-only -Wextra x3.cc
x3.cc:3:21: warning: comparison of integers of different signs: 'int' and 'unsigned int' [-Wsign-compare]
for (int i = 0; i < size; ++i)
~ ^ ~~~~
1 warning generated.
Este aviso requer a -Wextra
bandeira. O motivo é que existem
bases de código muito grandes em que o sinal incompatível nas comparações é extremamente comum. Embora esse aviso encontre alguns erros, a probabilidade do código ser um erro quando o usuário escreve é bastante baixa, em média. O resultado é uma taxa falso-positiva extremamente alta . No entanto, quando há um erro em um programa devido a regras de promoção estranhas, geralmente é extremamente sutil emitir esse aviso
quando sinaliza que um erro possui um valor relativamente alto . Como conseqüência, Clang fornece e expõe sob uma bandeira.
Normalmente, os avisos não ficam muito tempo fora da -Wextra
bandeira. Clang se esforça muito para não implementar avisos que não veem uso e teste regulares. Os avisos adicionais ativados -Weverything
normalmente são avisos em desenvolvimento ativo ou com erros ativos. Eles serão corrigidos e colocados sob sinalizadores apropriados ou deverão ser removidos.
Agora que entendemos como essas coisas funcionam com o Clang, vamos tentar voltar à pergunta original: que avisos você deve ativar para o seu desenvolvimento? A resposta é, infelizmente, que depende. Considere as seguintes perguntas para ajudar a determinar quais avisos funcionam melhor para sua situação.
- Você tem controle sobre todo o seu código ou é parte dele externo?
- Quais são seus objetivos? Pegando bugs ou escrevendo um código melhor?
- Qual é a sua tolerância falso-positiva? Você está disposto a escrever um código extra para silenciar avisos regularmente?
Em primeiro lugar, se você não controlar o código, não tente ativar avisos extras. Esteja preparado para desligar alguns. Existe muito código incorreto no mundo e talvez você não consiga consertar tudo. Está bem. Trabalhe para encontrar uma maneira de concentrar seus esforços no código que você controla.
Em seguida, descubra o que você deseja com seus avisos. Isso é diferente para pessoas diferentes. O Clang tentará avisar sem nenhuma opção sobre erros flagrantes ou padrões de código para os quais temos um longo histórico histórico indicando que a taxa de erros é extremamente alta. Ao permitir que -Wall
você receba um conjunto de avisos muito mais agressivo, destinado a detectar os erros mais comuns que os desenvolvedores do Clang observaram no código C ++. Mas com ambos, a
taxa de falso positivo deve permanecer bastante baixa.
Finalmente, se você estiver perfeitamente disposto a silenciar * falso-positivo * a cada passo, vá em frente -Wextra
. Arquive bugs se você observar avisos que estão capturando muitos bugs reais, mas com falsos positivos tolos ou inúteis. Estamos constantemente trabalhando para encontrar maneiras de trazer cada vez mais a lógica de detecção de erros presente -Wextra
para -Wall
onde podemos evitar os falsos positivos.
Muitos acharão que nenhuma dessas opções é a ideal para eles. No Google, desativamos alguns avisos -Wall
devido a muitos códigos existentes que violam o aviso. Também ativamos alguns avisos explicitamente, mesmo que não sejam ativados -Wall
, porque eles têm um valor particularmente alto para nós. Sua milhagem varia, mas provavelmente varia de maneiras semelhantes. Muitas vezes, pode ser muito melhor ativar alguns avisos importantes em vez de todos
-Wextra
.
Eu incentivaria todos a ativar -Wall
qualquer código não legado. Para o novo código, os avisos aqui são quase sempre valiosos e realmente aprimoram a experiência de desenvolvimento de código. Por outro lado, eu incentivaria todos a
não habilitar bandeiras além -Wextra
. Se você encontrar um aviso Clang que -Wextra
não inclui mas o que prova a todos valioso para você, simplesmente envie um erro e nós provavelmente pode colocá-la debaixo -Wextra
. Se você habilitar explicitamente algum subconjunto dos avisos -Wextra
dependerá muito do seu código, seu estilo de codificação e se a manutenção dessa lista é mais fácil do que consertar tudo o que foi descoberto -Wextra
.
Na lista de avisos do OP (que incluía ambos -Wall
e -Wextra
), apenas os seguintes avisos não são cobertos por esses dois grupos (ou ativados por padrão). O primeiro grupo enfatiza por que a dependência excessiva de sinalizadores de aviso explícitos pode ser ruim: nada disso é implementado no Clang! Eles são aceitos na linha de comando apenas para compatibilidade com o GCC.
-Wbad-function-cast
-Wdeclaration-after-statement
-Wmissing-format-attribute
-Wmissing-noreturn
-Wnested-externs
-Wnewline-eof
-Wold-style-definition
-Wredundant-decls
-Wsequence-point
-Wstrict-prototypes
-Wswitch-default
O próximo intervalo de avisos desnecessários na lista original são aqueles que são redundantes com os outros nessa lista:
-Wformat-nonliteral
-- Subconjunto de -Wformat=2
-Wshorten-64-to-32
-- Subconjunto de -Wconversion
-Wsign-conversion
-- Subconjunto de -Wconversion
Há também uma seleção de avisos que são mais categoricamente diferentes. Eles lidam com variantes de dialetos de idiomas, e não com códigos de buggy ou não. Com exceção de -Wwrite-strings
, todos esses são avisos para extensões de idioma fornecidas pelo Clang. O aviso de Clang sobre seu uso depende da prevalência da extensão. O Clang visa a compatibilidade com o GCC e, em muitos casos, facilita isso com extensões de idioma implícitas que são amplamente utilizadas. -Wwrite-strings
, como comentado no OP, é um sinalizador de compatibilidade do GCC que realmente altera a semântica do programa. Lamento profundamente esta bandeira, mas temos de apoiá-la devido ao legado que ela tem agora.
-Wfour-char-constants
-Wpointer-arith
-Wwrite-strings
As opções restantes que estão realmente ativando avisos potencialmente interessantes são:
-Wcast-align
-Wconversion
-Wfloat-equal
-Wformat=2
-Wimplicit-atomic-properties
-Wmissing-declarations
-Wmissing-prototypes
-Woverlength-strings
-Wshadow
-Wstrict-selector-match
-Wundeclared-selector
-Wunreachable-code
A razão pela qual elas não estão presentes -Wall
ou -Wextra
nem sempre é clara. Para muitos deles, eles são realmente baseado em avisos do CCG ( -Wconversion
,
-Wshadow
, etc.) e, como tal Clang tenta imitar o comportamento do GCC. Estamos lentamente dividindo alguns deles em avisos mais detalhados e úteis. Aqueles então têm uma maior probabilidade de fazer parte de um dos grupos de alerta de nível superior. Dito isto, escolher um aviso -Wconversion
é tão amplo que provavelmente continuará sendo sua própria categoria de "nível superior" no futuro próximo. Alguns outros avisos que o GCC possui, mas que têm baixo valor e altas taxas de falso positivo, podem ser relegados a uma terra de ninguém semelhante.
Outras razões pelas quais esses itens não estão em um dos baldes maiores incluem erros simples, problemas falsos positivos muito significativos e avisos em desenvolvimento. Vou examinar os erros de arquivamento para os que eu puder identificar. Todos eles devem migrar para um sinalizador de balde grande e apropriado ou ser removidos do Clang.
Espero que isso esclareça a situação de aviso com Clang e forneça algumas dicas para aqueles que tentam escolher um conjunto de avisos para seu uso ou uso de sua empresa.