Indicadores útiles de GCC para C

157

Más allá de la configuración -Wally la configuración -std=XXX, ¿qué otros indicadores de compilación realmente útiles, pero menos conocidos, existen para usar en C?

Estoy particularmente interesado en cualquier advertencia adicional, y / o convertir las advertencias en errores en algunos casos para minimizar absolutamente cualquier desajuste de tipo accidental.

Matt Joiner
fuente
9
Bueno -save-temps, -Wshadowy -fmudflapfueron los mejores hallazgos que no conocía, gracias a todos.
Matt Joiner
Contexto, por lo que puedo decir: correr gcc -c [flags-go-here] -o myprog.o myprog.cpara compilar (no vincular) un programa en C.
Rory O'Kane

Respuestas:

64

Varias de las -fopciones de generación de código son interesantes:

  • La -ftrapvfunción hará que el programa aborte en el desbordamiento de enteros con signo (formalmente "comportamiento indefinido" en C).

  • -fverbose-asmes útil si está compilando -Spara examinar la salida del ensamblaje; agrega algunos comentarios informativos.

  • -finstrument-functions agrega código para llamar a funciones de creación de perfiles proporcionadas por el usuario en cada punto de entrada y salida de funciones.

coste y flete
fuente
Para -ftrapv, eche un vistazo aquí stackoverflow.com/questions/20851061/… .. parece que hay un error que espera mucho tiempo para ser reparado.
Arjun Sreedharan
¿Puedes consultar el comentario anterior?
Suraj Jain
-ftrapv fue esencialmente reemplazado por -fsanitize =igned-integer-overflow.
Marc Glisse
139

Aquí están los míos:

  • -Wextra, -Wall: esencial.
  • -Wfloat-equal: útil porque generalmente probar números de coma flotante para determinar la igualdad es malo.
  • -Wundef: advierte si un identificador no inicializado se evalúa en una #ifdirectiva.
  • -Wshadow: advierte cuando una variable local sombrea otra variable local, parámetro o variable global o cuando una función incorporada está sombreada.
  • -Wpointer-arith: advierte si algo depende del tamaño de una función o de void.
  • -Wcast-align: avisa cada vez que se lanza un puntero de modo que se aumenta la alineación requerida del objetivo. Por ejemplo, advierta si char *se emite un int *en máquinas en las que solo se puede acceder a los enteros en límites de dos o cuatro bytes.
  • -Wstrict-prototypes: advierte si una función se declara o define sin especificar los tipos de argumento.
  • -Wstrict-overflow=5: advierte sobre casos en los que el compilador se optimiza en base al supuesto de que no se produce un desbordamiento firmado. (El valor 5 puede ser demasiado estricto, consulte la página del manual).
  • -Wwrite-strings: proporcione a las constantes de cadena la const char[longitud del tipo ]para que al copiar la dirección de uno en un no const char *puntero se obtenga una advertencia.
  • -Waggregate-return: advierte si alguna función que devuelve estructuras o uniones se define o llama.
  • -Wcast-qual: advierte cada vez que se lanza un puntero para eliminar un calificador de tipo del tipo de destino * .
  • -Wswitch-default: advierte siempre que una switchdeclaración no tenga un defaultcaso * .
  • -Wswitch-enum: advierte cuando una switchinstrucción tiene un índice de tipo enumerado y carece casede uno para uno o más de los códigos nombrados de esa enumeración * .
  • -Wconversion: advierte sobre conversiones implícitas que pueden alterar un valor * .
  • -Wunreachable-code: advierte si el compilador detecta que el código nunca se ejecutará * .

Los marcados * a veces dan demasiadas advertencias espurias, por lo que las uso según sea necesario.

Alok Singhal
fuente
11
Lista bastante completa, solo quiero agregar una más; -Wformat=2: Comprobaciones de formato adicionales en las funciones printf / scanf.
schot
1
¿No están todos implicados -Wall?
chacham15
2
@ chacham15, no, no lo creo. gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
Alok Singhal
1
@Alok hmm, ¿tal vez no es estándar entre las distribuciones? Sé que en mi mbp tengo que apagarlo explícitamente -Wwrite-stringsporque lo odio mucho.
chacham15
@ chacham15, tal vez. Pero la descripción de -Wwrite-stringsespecíficamente dice que no es parte de -Wall: gcc.gnu.org/onlinedocs/gcc/… . ¿Quizás algo más en su configuración está configurando esa bandera? ¿O tal vez estás compilando C ++?
Alok Singhal
52

Siempre use -Oo superior ( -O1, -O2, -Os, etc.). En el nivel de optimización predeterminado, gcc busca la velocidad de compilación y no hace suficiente análisis para advertir sobre cosas como variables unitarias.

Considere hacer una -Werrorpolítica, ya que las advertencias que no detienen la compilación tienden a ser ignoradas.

-Wall prácticamente enciende las advertencias que muy probablemente sean errores.

Las advertencias incluidas en -Wextratienden a marcar códigos comunes y legítimos. Pueden ser útiles para las revisiones de código (aunque los programas estilo pelusa encuentran que muchas más trampas son más flexibles), pero no los activaría para el desarrollo normal.

-Wfloat-equal es una buena idea si los desarrolladores del proyecto no están familiarizados con el punto flotante, y una mala idea si lo están.

-Winit-selfes útil; Me pregunto por qué no está incluido -Wuninitialized.

-Wpointer-arithes útil si tiene un código mayormente portátil con el que no funciona -pedantic.

Gilles 'SO- deja de ser malvado'
fuente
9
+1 para "-Wfloat-equal es una buena idea si los desarrolladores del proyecto no están familiarizados con el punto flotante, y una mala idea si lo están". especialmente la segunda mitad de la misma. :-)
R .. GitHub DEJA DE AYUDAR AL HIELO
39
-save-temps

Esto deja atrás los resultados del preprocesador y el ensamblaje.

La fuente preprocesada es útil para depurar macros.

El ensamblaje es útil para determinar qué optimizaciones entraron en vigencia. Por ejemplo, es posible que desee verificar que GCC está haciendo la optimización de llamadas de cola en algunas funciones recursivas, ya que sin ella puede desbordar la pila.

catphive
fuente
Me preguntaba cómo conseguiste que hiciera eso ... Siempre le pedí a gcc que volcara el ensamblaje si lo necesitaba.
35

Me sorprende que nadie haya dicho esto todavía: el indicador más útil en lo que a mí respecta es -gque coloca la información de depuración en el ejecutable para que pueda depurarla y pasar por la fuente (a menos que sea competente y lea el ensamblaje y como el stepicomando) de un programa mientras se está ejecutando.


fuente
35

-fmudflap : agrega comprobaciones de tiempo de ejecución a todas las operaciones de puntero arriesgadas para detectar UB. Esto efectivamente inmuniza su programa nuevamente desbordamientos de búfer y ayuda a atrapar todo tipo de punteros colgantes.

Aquí hay una demostración:

$ 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
fuente
Hmmm, el mudflap parece bastante desagradable: P
Matt Joiner
9
-fmudflapya no es compatible desde GCC 4.9, obtienes warning: switch '-fmudflap' is no longer supported. Fue reemplazado por AddressSanitizer.
Agostino
21

No está realmente relacionado con C / C ++, pero de todos modos es útil:

@file

Ponga todos los indicadores buenos anteriores (que todos han especificado) en un 'archivo', y use este indicador anterior para usar todos los indicadores en ese archivo juntos.

p.ej:

Archivo: compilerFlags

-Pared

-std = c99

-Wextra

Luego compila:

gcc yourSourceFile @compilerFlags
Amit Tomar
fuente
15

-march=native para producir código optimizado para la plataforma (= chip) en la que está compilando

Jens Gustedt
fuente
2
Si está compilando para máquinas no nativas donde no conoce el destino, puede usar mtune = xxx que optimiza sin usar conjuntos de instrucciones. Por ejemplo, mtune = generic se mantiene actualizado con los procesadores de casos "promedio".
Turix
15

Si necesita conocer los indicadores del preprocesador predefinidos por el compilador:

echo | gcc -E -dM -
sizzzzlerz
fuente
13

No es realmente útil para detectar errores, pero la -masm=intelopción rara vez mencionada hace que el uso -Spara inspeccionar la salida del ensamblaje sea mucho, mucho mejor.

La sintaxis de ensamblaje de AT&T me duele demasiado la cabeza.

Michael Burr
fuente
2
La diferencia entre AT&T e Intel para mí es la diferencia entre C # y Java. Solo sintaxis. Ambos horribles. :)
Matt Joiner el
2
+1 @michael para hacer que gcc use la sintaxis de Intel en lugar del horrible dios de & t. La inspección del ensamblaje utiliza suficientes ciclos cerebrales; no es necesario desperdiciar los ciclos cerebrales que src genera antes de los códigos de operación. Ahora, si solo gcc admite la línea __asm ​​{} como otros compiladores, ¡estamos listos!
greatwolf
10

Mi archivo MAKE típicamente contiene

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

La más importante de estas opciones se ha discutido antes, por lo que señalaré las dos características que aún no se han señalado:

A pesar de que estoy trabajando en una base de código que debe ser C simple para la portabilidad a alguna plataforma que todavía no tiene un compilador de C ++ decente, hago una compilación "extra" con el compilador de C ++ (además del compilador de C). Eso tiene 3 beneficios:

  1. el compilador de C ++ ocasionalmente me da mejores mensajes de advertencia que el compilador de C.
  2. El compilador de C ++ acepta la opción -Weffc ++, que ocasionalmente me da algunos consejos útiles, que me perdería si solo lo compilara en C.
  3. Puedo mantener el código relativamente fácil de portar a C ++, evitando algunas condiciones límite donde el código C simple es un código C ++ no válido (como definir una variable llamada "bool").

Sí, soy una Pollyanna irremediablemente optimista que sigue pensando que seguramente en cualquier mes una plataforma será declarada obsoleta o obtendrá un compilador decente de C ++, y finalmente podremos cambiar a C ++. En mi opinión, es inevitable: la única pregunta es si eso sucede antes o después de que la gerencia finalmente les eche a todos un pony. :-)

David Cary
fuente
Un buen punto al escribirlo como C ++, considero esto a menudo. (subconjunto naturalmente)
Matt Joiner
66
Debo señalar que C siendo obsoleto en favor de C ++ nunca sucederá, lo siento :)
Matt Joiner
44
considere -o / dev / null en lugar de rm -f junk
ulidtko
9
-Wstrict-prototypes -Wmissing-prototypes
ninjalj
fuente
10
Y -Wold-style-definitionsi tiene que lidiar con reincidentes que piensan que las funciones de estilo K&R son una buena idea, incluso con declaraciones prototipadas. (Tengo que tratar con personas así. Realmente me molesta cuando encuentro un nuevo código escrito en K&R. Ya es bastante malo tener cosas de K&R heredadas que no están arregladas, ¡pero un código nuevo! ¡Grump!)
Jonathan Leffler
9

Aquí hay una gran bandera que no se ha mencionado:

-Werror-implicit-function-declaration

Dar un error cada vez que se utiliza una función antes de ser declarada.

Matt Joiner
fuente
8
man gcc

El manual está lleno de banderas interesantes con buenas descripciones. Sin embargo, -Wall probablemente hará que gcc sea lo más detallado posible. Si desea datos más interesantes, debería echar un vistazo a valgrind o alguna otra herramienta para verificar errores.

Johan
fuente
1
Sin embargo, es muuuuuuuuuuuuy largo. man gcc | nlreporta más de 11000 líneas. ¡Eso es más que la infame página de bashmanual!
nuevo123456
12
Gracias a Dios, lo incluyeron en una página de manual, en lugar de una de esas páginas de "información" imposibles de navegar.
Matt Joiner el
6

Bueno, también -Wextradebería ser estándar. -Werrorconvierte las advertencias en errores (que pueden ser muy molestos, especialmente si compila sin ellos -Wno-unused-result). -pedanticen combinación constd=c89 le da advertencias adicionales si utiliza las funciones C99.

Pero eso es todo. No puede sintonizar un compilador de C en algo más de ahorro de texto que C en sí.

RWS
fuente
6

-M* familia de opciones.

Estos le permiten escribir archivos que determinan automáticamente de qué archivos de encabezado deberían depender sus archivos fuente c o c ++. GCC generará archivos de creación con esta información de dependencia y luego los incluirá desde su archivo de creación principal.

Aquí hay un ejemplo de un archivo MAKE extremadamente genérico que usa -MD y -MP que compilará un directorio lleno de archivos de origen y encabezado de c ++, y descubrirá todas las dependencias automáticamente:

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

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

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

Aquí hay una publicación de blog que lo analiza con más profundidad: http://www.microhowto.info/howto/automatically_generate_makefile_dependencies.html

catphive
fuente
6

Existe -Werror, que trata todas las advertencias como errores y detiene la compilación. La gccpágina del manual explica cada cambio de línea de comando para su compilador.

Greg Hewgill
fuente
@Matt Joiner: Dado que no mencionó qué arquitectura de máquina está utilizando, los gccindicadores pueden ser diferentes entre los suyos y cualquier vínculo que alguien sugiera. Esta es la razón por la cual se suministran páginas de manual con su software.
Greg Hewgill el
4

-Wfloat-equal

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

Una de las otras advertencias nuevas que me gustan es -Wfloat-equal. Ese avisa siempre que [tenga] un número de coma flotante en una condición de igualdad. Eso es brillante! Si cada uno ha programado un gráfico de computadora o (peor :) algoritmo de geometría computacional, sabrá que nunca hay dos flotadores que coincidan con la igualdad ...

semental
fuente
10
Mis flotadores no coinciden con la igualdad, ya que sé lo que estoy haciendo.
Roland Illig el
4

Encontré este hilo buscando una bandera para solucionar un problema específico, no lo veo aquí, así que agregaré uno que me estaba confundiendo en mi publicación :

La -Wformat=2bandera

-Wformat=> Verifique las llamadas a printfy scanf, etc., para asegurarse de que los argumentos proporcionados tengan tipos apropiados para la cadena de formato especificada ...

Y la parte realmente importante al respecto ( según el manual de GCC ):

-Wformatse incluye en -Wall. Para obtener más control sobre algunos aspectos del formato de cheques, las opciones -Wformat-y2k, -Wno-format-extra-args, -Wno-format-zero-length, -Wformat-nonliteral, -Wformat-security, y -Wformat=2están disponibles, pero no se incluyen en -Wall.`

Entonces, solo porque tienes -Wallno significa que lo tengas todo. ;)

Miguel
fuente
3

A veces lo uso -spara un ejecutable mucho más pequeño:

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

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

Vasiliy Sharapov
fuente
66
solo debe ejecutar stripsu binario, de esta manera puede tener un binario con información de depuración, eliminarlo más tarde para su distribución.
Hasturkun
Sí, striptambién funciona , pero -spuede ser más rápido y fácil, aunque no es tan elaborado como correrstrip
Vasiliy Sharapov
3

Si bien esta respuesta puede estar un poco fuera de tema y la pregunta es un digno +1 para mí, ya que

Estoy particularmente interesado en cualquier advertencia adicional, y / o convertir las advertencias en errores en algunos casos para minimizar absolutamente cualquier desajuste de tipo accidental.
hay una herramienta que debería detectar TODOS los errores y posibles errores que pueden no ser obvios, hay una férula que, en mi humilde opinión, hace un mejor trabajo para detectar errores en comparación con gcc o cualquier otro compilador. Esa es una herramienta digna de tener en su caja de herramientas.

La comprobación estática a través de una herramienta tipo pelusa, como la férula, debería haber sido parte de una cadena de herramientas del compilador.

t0mm13b
fuente
Siempre muestra que un error no puede presentar el archivo del preprocesador en C: \ include, no estoy seguro de qué hacer
Suraj Jain
2

Estoy particularmente interesado en cualquier advertencia adicional,

Además -Wall, la opción -Wo -Wextra( -Wfunciona con versiones anteriores de gcc así como con las más nuevas; las versiones más recientes admiten el nombre alternativo -Wextra, que significa lo mismo, pero es más descriptivo) habilita varias advertencias adicionales.

También hay aún más advertencias que no están habilitadas por ninguno de ellos, generalmente para cosas que son más cuestionables. El conjunto de opciones disponibles depende de la versión de gcc que esté utilizando; consulte man gcco info gccpara obtener más información, o consulte la documentación en línea para la versión de gcc en particular que le interese. Y -pedanticemite todas las advertencias requeridas por el estándar particular que se está utilizando (que depende en otras opciones como -std=xxxo -ansi) y se queja sobre el uso de extensiones gcc.

y / o convertir advertencias en errores en algunos casos para minimizar absolutamente cualquier desajuste de tipo accidental.

-Werrorconvierte todas las advertencias en errores. Sin embargo, no creo que gcc le permita hacer eso selectivamente para advertencias particulares.

Probablemente encontrará que tiene que ser selectivo sobre qué advertencias están habilitadas para cada proyecto (especialmente si lo usa -Werror), ya que los archivos de encabezado de bibliotecas externas pueden disparar algunas de ellas. ( -pedanticen particular tiende a ser inútil a este respecto, en mi experiencia).

Matthew Slattery
fuente
44
"Sin embargo, no creo que gcc le permita hacer eso selectivamente para advertencias particulares". En realidad, puedes con -Werror=some-warning.
Matthew Flaschen
0
  • -Wmissing-prototypes: Si una función global se define sin una declaración de prototipo previa.
  • -Wformat-security: Advierte sobre los usos de las funciones de formato que representan posibles problemas de seguridad. En la actualidad, esto advierte sobre llamadas printfy scanffunciones donde la cadena de formato no es un literal de cadena y no hay argumentos de formato
Praveen Handigol
fuente
0
  • -Werror=return-type: Aplicar error cuando la función no tiene retorno en gcc. Está /we4716en Visual Studio.

  • -Werror=implicit-function-declaration: Aplicar error cuando la función se utiliza sin definido / no incluido. Está /we4013en Visual Studio.

  • -Werror=incompatible-pointer-types: Enfore error cuando el tipo de un puntero no coincide con el tipo de puntero esperado. Está /we4133en Visual Studio.

En realidad, me gustaría mantener mi código C multiplataforma, y ​​uso CMake, y pongo los cflags proporcionados en 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
fuente