Sinalizadores úteis do GCC para C

157

Além da configuração -Walle da configuração -std=XXX, que outros sinalizadores de compilador realmente úteis, mas menos conhecidos, existem para uso em C?

Estou particularmente interessado em avisos adicionais e / ou em transformar avisos em erros em alguns casos para minimizar absolutamente qualquer incompatibilidade acidental de tipo.

Matt Joiner
fonte
9
Bem -save-temps, -Wshadowe -fmudflapforam as melhores descobertas que eu não conhecia, graças a todos.
Matt Joiner
Contexto, tanto quanto posso dizer: executando gcc -c [flags-go-here] -o myprog.o myprog.cpara compilar (não vincular) um programa em C.
Rory O'Kane

Respostas:

64

Várias -fopções de geração de código são interessantes:

  • A -ftrapvfunção fará com que o programa seja interrompido por excesso de número inteiro assinado (formalmente "comportamento indefinido" em C).

  • -fverbose-asmé útil se você estiver compilando -Spara examinar a saída do assembly - ele adiciona alguns comentários informativos.

  • -finstrument-functions adiciona código para chamar funções de criação de perfil fornecidas pelo usuário em cada ponto de entrada e saída de função.

caf
fonte
Para -ftrapv, dê uma olhada aqui stackoverflow.com/questions/20851061/… .. parece que há um bug que está há muito tempo aguardando para ser corrigido.
Arjun Sreedharan /
Você pode verificar o comentário acima?
Suraj Jain
-ftrapv foi essencialmente substituído por -fsanitize = overflow de número inteiro assinado.
Marc Glisse
139

Aqui estão os meus:

  • -Wextra, -Wall: essencial.
  • -Wfloat-equal: útil, porque geralmente testar números de ponto flutuante quanto à igualdade é ruim.
  • -Wundef: avisa se um identificador não inicializado é avaliado em uma #ifdiretiva.
  • -Wshadow: avisa sempre que uma variável local sombreia outra variável local, parâmetro ou variável global ou sempre que uma função interna é sombreada.
  • -Wpointer-arith: avisa se alguma coisa depende do tamanho de uma função ou de void.
  • -Wcast-align: avisa sempre que um ponteiro é convertido, de modo que o alinhamento necessário do alvo seja aumentado. Por exemplo, avise se a char *é convertido em uma int *máquina em que números inteiros só podem ser acessados ​​em limites de dois ou quatro bytes.
  • -Wstrict-prototypes: avisa se uma função é declarada ou definida sem especificar os tipos de argumento.
  • -Wstrict-overflow=5: avisa sobre casos em que o compilador otimiza com base na suposição de que o estouro assinado não ocorre. (O valor 5 pode ser muito rigoroso, consulte a página do manual.)
  • -Wwrite-strings: dê às constantes da string o const char[comprimento do tipo ]para que a cópia do endereço de uma para um não const char *ponteiro receba um aviso.
  • -Waggregate-return: avisa se alguma função que retorna estruturas ou uniões é definida ou chamada.
  • -Wcast-qual: avisa sempre que um ponteiro é convertido para remover um qualificador de tipo do tipo de destino * .
  • -Wswitch-default: avisa sempre que uma switchinstrução não tem um defaultcaso * .
  • -Wswitch-enum: avisa sempre que uma switchinstrução possui um índice do tipo enumerado e não possui um casepara um ou mais dos códigos nomeados dessa enumeração * .
  • -Wconversion: avise sobre conversões implícitas que podem alterar um valor * .
  • -Wunreachable-code: avisa se o compilador detectar que o código nunca será executado * .

Os marcados com * às vezes dão muitos avisos falsos, então eu os uso conforme a necessidade.

Alok Singhal
fonte
11
Lista bastante completa, só quero adicionar mais uma; -Wformat=2: Verificações de formato extra nas funções printf / scanf.
schot
1
arent tudo isso implicado por -Wall?
chacham15
2
@ chacham15, não, acho que não. gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
Alok Singhal
1
@ Alok hmm, talvez não seja padrão entre as distribuições? Eu sei que no meu mbp eu tenho que desligar explicitamente -Wwrite-stringsporque eu odeio muito.
chacham15
@ chacham15, talvez. Mas a descrição para -Wwrite-stringsespecificamente diz que não faz parte de -Wall: gcc.gnu.org/onlinedocs/gcc/… . Talvez algo mais na sua configuração esteja definindo esse sinalizador? Ou talvez você esteja compilando C ++?
Alok Singhal
52

Sempre usar -Oou acima ( -O1, -O2, -Os, etc.). No nível de otimização padrão, o gcc busca a velocidade de compilação e não faz análises suficientes para avisar sobre coisas como variáveis ​​unitizadas.

Considere fazer -Werrorpolítica, pois os avisos que não param a compilação tendem a ser ignorados.

-Wall praticamente ativa os avisos que provavelmente são erros.

Os avisos incluídos -Wextratendem a sinalizar códigos comuns e legítimos. Eles podem ser úteis para revisões de código (embora os programas no estilo fiapo achem muito mais armadilhas são mais flexíveis), mas eu não os ativaria para o desenvolvimento normal.

-Wfloat-equal é uma boa idéia se os desenvolvedores do projeto não estiverem familiarizados com o ponto flutuante e uma má idéia se estiverem.

-Winit-selfé útil; Eu me pergunto por que não está incluído -Wuninitialized.

-Wpointer-arithé útil se você tiver um código principalmente portátil que não funcione -pedantic.

Gilles 'SO- parar de ser mau'
fonte
9
+1 para "-Wfloat-equal é uma boa idéia se os desenvolvedores do projeto não estiverem familiarizados com o ponto flutuante e uma má idéia se estiverem." especialmente a segunda metade. :-)
R .. GitHub Pare de ajudar o gelo
39
-save-temps

Isso deixa para trás os resultados do pré-processador e da montagem.

A fonte pré-processada é útil para depurar macros.

A montagem é útil para determinar quais otimizações entraram em vigor. Por exemplo, convém verificar se o GCC está otimizando a chamada de cauda em algumas funções recursivas, pois sem ela você pode potencialmente sobrecarregar a pilha.

catphive
fonte
Eu me perguntei como você conseguiu fazer isso ... Eu sempre pedi ao GCC para despejar a montagem, se eu precisasse.
35

Estou surpreso que ninguém tenha dito isso ainda - o sinalizador mais útil para mim é -gque coloca as informações de depuração no executável, para que você possa depurá-las e percorrer a fonte (a menos que seja proficiente e esteja lendo a montagem e como o stepicomando) de um programa enquanto estiver em execução.


fonte
35

-fmudflap - adiciona verificações de tempo de execução a todas as operações arriscadas do ponteiro para capturar o UB. Isso efetivamente imuniza seu programa novamente, estouros de buffer e ajuda a capturar todos os tipos de ponteiros pendentes.

Aqui está uma demonstração:

$ cat mf.c 
int main()
{
 int a[10];
 a[10]=1; // <-- o noes, line 4
}

$ gcc -fmudflap mf.c -lmudflap
$ ./a.out 
*******
mudflap violation 1 (check/write): time=1280862302.170759 ptr=0x7fff96eb3d00 size=44
pc=0x7f3a575503c1 location=`mf.c:4:2 (main)'
      /usr/lib/libmudflap.so.0(__mf_check+0x41) [0x7f3a575503c1]
      ./a.out(main+0x90) [0x400a54]
      /lib/libc.so.6(__libc_start_main+0xfd) [0x7f3a571e2c4d]
Nearby object 1: checked region begins 0B into and ends 4B after
mudflap object 0xf9c560: name=`mf.c:3:6 (main) a'
bounds=[0x7fff96eb3d00,0x7fff96eb3d27] size=40 area=stack check=0r/3w liveness=3
alloc time=1280862302.170749 pc=0x7f3a57550cb1
number of nearby objects: 1
Mainframe nórdico
fonte
Hmmm, mudflap parece muito desagradável: P #
Matt Joiner
9
-fmudflapnão é mais suportado desde o GCC 4.9, você recebe warning: switch '-fmudflap' is no longer supported. Foi substituído pelo AddressSanitizer.
Agostino
21

Não é realmente relacionado ao C / C ++, mas é útil de qualquer maneira:

@file

Coloque todos os sinalizadores válidos acima (todos que você especificou) em um 'arquivo' e use este sinalizador acima para usar todos os sinalizadores nesse arquivo juntos.

por exemplo:

Arquivo: compilerFlags

-Parede

-std = c99

-Wextra

Em seguida, compile:

gcc yourSourceFile @compilerFlags
Amit Tomar
fonte
15

-march=native para produzir código otimizado para a plataforma (= chip) na qual você está compilando

Jens Gustedt
fonte
2
Se você estiver compilando para máquinas não nativas nas quais não conhece o destino, poderá usar mtune = xxx, que otimiza sem usar conjuntos de instruções. Por exemplo, mtune = generic é mantido atualizado com os processadores de caso "médios".
Turix
15

Se você precisar conhecer os sinalizadores de pré-processador predefinidos pelo compilador:

echo | gcc -E -dM -
sizzzzlerz
fonte
13

Não é realmente útil para detectar erros, mas a -masm=intelopção raramente mencionada torna o uso-S a inspeção do resultado da montagem seja muito mais agradável.

A sintaxe da montagem da AT&T machuca minha cabeça demais.

Michael Burr
fonte
2
A diferença entre AT&T e Intel para mim é a diferença entre C # e Java. Apenas sintaxe. Ambos horríveis. :)
Marceneiro de Matt
2
+1 a @michael por fazer com que o gcc use a sintaxe intel em vez do deus terrível na & t. A inspeção da montagem usa ciclos cerebrais suficientes - não há necessidade de desperdiçar ciclos cerebrais que o src preceda os códigos de destino. Agora, se apenas o gcc suporta o __asm ​​{} inline, como outros compiladores, estamos prontos!
bisavô
10

Meu makefile normalmente contém

  CFLAGS= -Wall -Wextra -Weffc++ -Os -ggdb
  ...
  g++ $(CFLAGS) -o junk $<
  gcc $(CFLAGS) -o $@ $<
  rm -f junk

As mais importantes dessas opções já foram discutidas antes, por isso vou apontar os dois recursos que ainda não foram apontados:

Mesmo trabalhando em uma base de código que precisa ser C simples para portabilidade para alguma plataforma que ainda não possui um compilador C ++ decente, eu faço uma compilação "extra" com o compilador C ++ (além do compilador C). Isso tem três benefícios:

  1. ocasionalmente, o compilador C ++ me fornece mensagens de aviso melhores que o compilador C.
  2. O compilador C ++ aceita a opção -Weffc ++, que ocasionalmente me dá algumas dicas úteis, que eu perderia se apenas o compilasse em C.
  3. Posso manter o código relativamente fácil de portar para o C ++, evitando algumas condições de contorno em que o código C simples é um código C ++ inválido (como definir uma variável chamada "bool").

Sim, sou uma Pollyanna irremediavelmente otimista que fica pensando que certamente a qualquer mês, agora que uma plataforma será declarada obsoleta ou ganhará um compilador C ++ decente, e finalmente podemos mudar para C ++. Na minha opinião, é inevitável - a única questão é se isso acontece antes ou depois da administração finalmente emitir um pônei para todos. :-)

David Cary
fonte
Um bom ponto de escrevê-lo como C ++, considero isso com frequência. (subconjunto naturalmente)
Matt Joiner
6
Gostaria de salientar que C sendo preterido em favor do C ++ nunca vai acontecer, desculpe :)
Matt Joiner
4
considere -o / dev / null em vez de rm -f junk
ulidtko
9
-Wstrict-prototypes -Wmissing-prototypes
ninjalj
fonte
10
E -Wold-style-definitionse você precisar lidar com reincidentes que pensam que as funções do estilo K&R são uma boa idéia, mesmo com declarações com protótipos. (Eu tenho que lidar com pessoas assim. Realmente me irrita quando encontro um novo código escrito em K&R. Já é ruim o suficiente ter material K&R herdado que não é fixo, mas novo código! Grump !!!)
Jonathan Leffler
9

Aqui está uma grande bandeira que não foi mencionada:

-Werror-implicit-function-declaration

Dê um erro sempre que uma função for usada antes de ser declarada.

Matt Joiner
fonte
8
man gcc

O manual está cheio de sinalizadores interessantes com boas descrições. No entanto, -Wall provavelmente tornará o gcc o mais detalhado possível. Se você deseja dados mais interessantes, consulte o valgrind ou alguma outra ferramenta para verificar se há erros.

Johan
fonte
1
É loooooooooooooooooooooooooooooooongong, no entanto. man gcc | nlrelata mais de 11000 linhas. Isso é mais do que a infame página de bashmanual!
new123456
12
Graças a Deus eles o colocaram em uma página de manual, em vez de em uma daquelas páginas de "informações" inevitáveis.
Matt Joiner
6

Bem, também -Wextradeve ser padrão. -Werrortransforma avisos em erros (o que pode ser muito irritante, especialmente se você compilar sem -Wno-unused-result). -pedanticem combinação com std=c89fornece avisos adicionais se você usar os recursos do C99.

Mas é isso aí. Você não pode ajustar um compilador C em algo mais salvo em tipo do que o próprio C.

RWS
fonte
6

-M* família de opções.

Isso permite que você escreva arquivos make que descobrem automaticamente em quais arquivos de cabeçalho seus arquivos de origem c ou c ++ devem depender. O GCC gerará arquivos make com essas informações de dependência e você os incluirá em seu arquivo make principal.

Aqui está um exemplo de um makefile extremamente genérico usando -MD e -MP que irá compilar um diretório cheio de arquivos de código-fonte e cabeçalho c ++ e descobrir todas as dependências automaticamente:

CPPFLAGS += -MD -MP                                         
SRC = $(wildcard *.cpp)                                                       

my_executable: $(SRC:%.cpp=%.o)                                                        
        g++ $(LDFLAGS) -o $@ $^                                               

-include $(SRC:%.cpp=%.d)

Aqui está uma postagem de blog que discute isso em mais profundidade: http://www.microhowto.info/howto/automatically_generate_makefile_dependencies.html

catphive
fonte
6

Existe -Werror, que trata todos os avisos como erros e interrompe a compilação. A gccpágina do manual explica cada opção de linha de comando para o seu compilador.

Greg Hewgill
fonte
@ Joiner Matt: Como você não mencionou qual arquitetura de máquina está usando, os gccsinalizadores podem ser diferentes entre os seus e o link que alguém possa sugerir. É por isso que as páginas de manual são fornecidas com o seu software.
Greg Hewgill
4

-Wfloat-equal

De: http://mces.blogspot.com/2005/07/char-const-argv.html

Um dos outros novos avisos que eu gosto é o -Wfloat-equal. Isso avisa sempre que você [possui] um número de ponto flutuante em uma condição de igualdade. Isso é brilhante! Se você já programou uma computação gráfica ou (pior :) algoritmo de geometria computacional, sabe que nunca há dois carros alegóricos iguais com a igualdade ...

viga
fonte
10
Meus carros alegóricos não combinar com a igualdade, como eu sei o que estou fazendo.
Roland Illig 9/08/10
4

Encontrei este tópico procurando por um sinalizador para corrigir um problema específico, não o vejo aqui, então vou adicionar um que estava me impressionando na minha postagem :

A -Wformat=2bandeira

-Wformat=> Verificar chamadas para printfe scanf, etc., para se certificar de que os argumentos fornecidos têm tipos apropriados para a cadeia de formato especificado ...

E a parte realmente importante sobre isso (de acordo com o manual do GCC ):

-Wformatestá incluído no -Wall. Para mais controle sobre alguns aspectos do formato de verificação, as opções -Wformat-y2k, -Wno-format-extra-args, -Wno-format-zero-length, -Wformat-nonliteral, -Wformat-security, e -Wformat=2estão disponíveis, mas não estão incluídos no -Wall.`

Então, só porque você tem -Wall, não significa que você tem tudo. ;)

Mike
fonte
3

Às vezes eu uso -spara um executável muito menor:

-s
    Remove all symbol table and relocation information from the executable.

Fonte: http://gcc.gnu.org/onlinedocs/gcc/Link-Options.html#Link-Options

Vasiliy Sharapov
fonte
6
você deve apenas rodar stripno seu binário, assim você pode ter um binário com informações de depuração, removê-lo mais tarde para distribuição.
Hasturkun
Sim, stripfunciona também, mas -spode ser mais rápido e mais fácil, embora não seja tão elaborado como correrstrip
Vasiliy Sharapov
3

Embora essa resposta possa ser um pouco fora do tópico e a pergunta seja um +1 digno de mim, pois

Estou particularmente interessado em avisos adicionais e / ou em transformar avisos em erros em alguns casos para minimizar absolutamente qualquer incompatibilidade acidental de tipo.
existe uma ferramenta que deve detectar TODOS os erros e possíveis erros que podem não ser óbvios; existe uma tala que IMHO faz um trabalho muito melhor na detecção de erros em comparação com o gcc ou qualquer outro compilador. Essa é uma ferramenta digna de ter no seu baú de ferramentas.

A verificação estática por meio de uma ferramenta do tipo fiapo, como o splint, deveria ter sido parte de uma cadeia de ferramentas do compilador.

t0mm13b
fonte
Ele sempre mostra um erro não pode arquivar arquivo de pré-processamento em C: \ incluem, eu não sei o que fazer
Suraj Jain
2

Estou particularmente interessado em quaisquer avisos adicionais,

Além de -Wall, a opção -Wou -Wextra(-W funciona com versões mais antigas do gcc e com as mais recentes; versões mais recentes suportam o nome alternativo -Wextra, o que significa a mesma coisa, mas é mais descritivo) permite vários avisos adicionais.

Também há ainda mais avisos que não são ativados por nenhum deles, geralmente para coisas que são mais questionáveis. O conjunto de opções disponíveis depende de qual versão do gcc você está usando - consulte man gccou info gccpara obter detalhes, ou consulte a documentação on - line da versão específica do gcc em que está interessado. E -pedanticemite todos os avisos exigidos pelo padrão em particular (que depende em outras opções como -std=xxxou -ansi) e reclama do uso de extensões gcc.

e / ou transformar avisos em erros em alguns casos para minimizar absolutamente qualquer incompatibilidade acidental de tipo.

-Werrortransforma todos os avisos em erros. Eu não acho que o gcc permita que você faça isso seletivamente para avisos específicos, no entanto.

Você provavelmente descobrirá que precisa ser seletivo sobre quais avisos são ativados por projeto (especialmente se você usar -Werror), pois os arquivos de cabeçalho de bibliotecas externas podem disparar alguns deles. ( -pedanticem particular, tende a ser inútil a esse respeito, na minha experiência.)

Matthew Slattery
fonte
4
"Mas não acho que o gcc permita que você faça isso seletivamente para avisos específicos". Na verdade, você pode com -Werror=some-warning.
Matthew Flaschen
0
  • -Wmissing-prototypes: Se uma função global for definida sem uma declaração de protótipo anterior.
  • -Wformat-security: Avisa sobre o uso de funções de formato que representam possíveis problemas de segurança. No momento, isso avisa sobre chamadas printfe scanffunções em que a cadeia de formato não é literal e não há argumentos de formato
Praveen Handigol
fonte
0
  • -Werror=return-type: Aplica erro quando a função não tem retorno no gcc. Está /we4716no Visual Studio.

  • -Werror=implicit-function-declaration: Aplica erro quando a função é usada sem definida / não incluída. Está /we4013no Visual Studio.

  • -Werror=incompatible-pointer-types: Erro inicial quando o tipo de um ponteiro não corresponde ao tipo de ponteiro esperado. Está /we4133no Visual Studio.

Na verdade, eu gostaria de manter meu código C em várias plataformas e uso o CMake, e coloquei os cflags fornecidos no CMakeLists.txt como:

if (CMAKE_SYSTEM_NAME MATCHES "Windows")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /we4013 /we4133 /we4716")
elseif (CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_SYSTEM_NAME MATCHES "Darwin")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror=implicit-function-declaration -Werror=incompatible-pointer-types -Werror=return-type")
endif()
HaxtraZ
fonte