c++ c warnings compiler-warnings

c++ - ¿Por qué debería habilitar siempre las advertencias del compilador?



warnings compiler-warnings (14)

¿Por qué habilitar advertencias?

Los compiladores de C y C ++ son notoriamente malos para informar algunos errores comunes del programador por defecto , como:

  • olvidando inicializar una variable
  • olvidando return un valor de una función
  • argumentos en las familias printf y scanf que no coinciden con la cadena de formato
  • una función se usa sin ser declarada de antemano (solo C)

Estos pueden ser detectados e informados, generalmente no de manera predeterminada; Esta característica debe solicitarse explícitamente a través de las opciones del compilador.

¿Cómo habilitar las advertencias?

Esto depende de tu compilador.

Los compiladores de Microsoft C y C ++ entienden modificadores como /W1 , /W2 , /W3 , /W4 y /Wall . Utilice al menos /W3 . /W4 y /Wall pueden emitir advertencias falsas para los archivos de encabezado del sistema, pero si su proyecto se compila limpiamente con una de estas opciones, hágalo. Estas opciones son mutuamente excluyentes.

La mayoría de los otros compiladores entienden opciones como -Wall , -Wpedantic y -Wextra . -Wall es esencial y se recomienda todo lo demás (tenga en cuenta que, a pesar de su nombre, -Wall solo permite las advertencias más importantes, no todas ). Estas opciones se pueden usar por separado o todas juntas.

Su IDE puede tener una forma de habilitarlos desde la interfaz de usuario.

¿Por qué tratar las advertencias como errores? ¡Son solo advertencias!

Una advertencia del compilador indica un problema potencialmente grave en su código. Los problemas enumerados anteriormente son casi siempre fatales; otros pueden o no serlo, pero desea que la compilación falle incluso si resulta ser una falsa alarma. Investigue cada advertencia, encuentre la causa raíz y corríjala. En el caso de una falsa alarma, evítelo, es decir, use una función o construcción de idioma diferente para que la advertencia ya no se active. Si esto resulta ser muy difícil, deshabilite esa advertencia en particular caso por caso.

No desea dejar solo advertencias como advertencias, incluso si todas son falsas alarmas. Podría estar bien para proyectos muy pequeños donde el número total de advertencias emitidas es inferior a 7. Algo más, y es fácil que una nueva advertencia se pierda en una inundación de viejas y conocidas. No permitas eso. Simplemente haga que todo su proyecto se compile limpiamente.

Tenga en cuenta que esto se aplica al desarrollo del programa. Si está lanzando su proyecto al mundo en forma de fuente, entonces puede ser una buena idea no proporcionar -Werror o equivalente en su script de compilación lanzado . La gente podría intentar construir su proyecto con una versión diferente del compilador, o con un compilador completamente diferente, que puede tener habilitado un conjunto diferente de advertencias. Es posible que desee que su construcción tenga éxito. Todavía es una buena idea mantener las advertencias habilitadas, de modo que las personas que vean mensajes de advertencia puedan enviarle informes de errores o parches.

¿Cómo tratar las advertencias como errores?

Esto se hace nuevamente con los modificadores del compilador. /WX es para Microsoft, la mayoría de los demás usan -Werror . En cualquier caso, la compilación fallará si se producen advertencias.

A menudo escucho que al compilar programas C y C ++ debería "habilitar siempre las advertencias del compilador". ¿Por qué es esto necesario? ¿Cómo puedo hacer eso?

A veces también escucho que debo "tratar las advertencias como errores". ¿Debería? ¿Cómo puedo hacer eso?


Las advertencias no fijas , tarde o temprano, conducirán a errores en su código .

La depuración de una falla de segmentación, por ejemplo, requiere que el programador rastree la raíz (causa) de la falla, que generalmente se encuentra en un lugar anterior en su código que la línea que eventualmente causó la falla de segmentación.

Es muy típico que la causa sea una línea para la cual el compilador emitió una advertencia que usted ignoró, y la línea que causó la segmentación falla la línea que finalmente arrojó el error.

Arreglar la advertencia lleva a solucionar el problema. ¡Un clásico!

Una demostración de lo anterior. Considere el siguiente código:

#include <stdio.h> int main(void) { char* str = "Hello world!"; int idx; // Colossal amount of code here, irrelevant to ''idx'' printf("%c/n", str[idx]); return 0; }

que cuando se compila con el indicador "Wextra" pasado a GCC, da:

main.c: In function ''main'': main.c:9:21: warning: ''idx'' is used uninitialized in this function [-Wuninitialized] 9 | printf("%c/n", str[idx]); | ^

que podría ignorar y ejecutar el código de todos modos ... Y luego sería testigo de una "gran" falla de segmentación, como solía decir mi profesor de IP epicurus:

Fallo de segmentación

Para depurar esto en un escenario del mundo real, uno comenzaría desde la línea que causa la falla de segmentación e intentará rastrear cuál es la raíz de la causa. Tendrían que buscar lo que le sucedió a i y str dentro de ese colosal cantidad de código por allá ...

Hasta que, un día, se encontraron en la situación en la que el descubrimiento de que se usa sin inicializar, por lo tanto, tiene un valor de basura, lo que resulta en la indexación de la cadena más allá de sus límites, lo que conduce a una falla de segmentación.

Si no hubieran ignorado la advertencia, ¡habrían encontrado el error de inmediato!


Alguna advertencia puede significar un posible error semántico en el código o una posible UB. Por ejemplo ; después de if() , variable no utilizada, variable global enmascarada por local, o comparación de firmado y no firmado. Muchas advertencias están relacionadas con el analizador de código estático en el compilador o con las infracciones del estándar ISO detectables en el momento de la compilación, que "requieren diagnósticos". Si bien esas ocurrencias pueden ser legales en un caso particular, serían el resultado de problemas de diseño la mayor parte del tiempo.

Algunos compiladores, por ejemplo, gcc, tienen una opción de línea de comando para activar el modo "advertencias como errores", es una herramienta agradable, aunque cruel, para educar a los programadores novatos.


C es, famoso, un lenguaje de bajo nivel a medida que avanzan las HLL. C ++, aunque puede parecer un lenguaje de nivel considerablemente más alto que C, todavía comparte algunos de sus rasgos. Y uno de esos rasgos es que los lenguajes fueron diseñados por programadores, para programadores y, específicamente, programadores que sabían lo que estaban haciendo.

[Para el resto de esta respuesta, me centraré en C. La mayor parte de lo que diré también se aplica a C ++, aunque quizás no con tanta fuerza. Aunque, como dijo Bjarne Stroustrup, "C hace que te resulte fácil dispararte en el pie; C ++ lo hace más difícil, pero cuando lo haces, te arrancas toda la pierna". ]

Si sabe lo que está haciendo, realmente sabe lo que está haciendo, a veces puede que tenga que "romper las reglas". Pero la mayoría de las veces, la mayoría de nosotros estaremos de acuerdo en que las reglas bien intencionadas nos mantienen a todos fuera de problemas, y que romper esas reglas todo el tiempo es una mala idea.

Pero en C y C ++, hay un número sorprendentemente grande de cosas que puede hacer que son "malas ideas" pero que no están formalmente "en contra de las reglas". A veces son una mala idea algunas veces (pero pueden ser defendibles otras veces); a veces son una mala idea prácticamente todo el tiempo. Pero la tradición siempre ha sido no advertir sobre estas cosas, porque, de nuevo, la suposición es que los programadores saben lo que están haciendo, no estarían haciendo estas cosas sin una buena razón, estarían molestos por un montón de advertencias innecesarias.

Pero, por supuesto, no todos los programadores realmente saben lo que están haciendo. Y, en particular, cada programador C (sin importar la experiencia) pasa por una fase de ser un programador C inicial. E incluso los programadores experimentados de C pueden descuidarse y cometer errores.

Finalmente, la experiencia ha demostrado no solo que los programadores cometen errores, sino que estos errores pueden tener consecuencias reales y graves. Si comete un error, y el compilador no le advierte al respecto, y de alguna manera el programa no se bloquea de inmediato o hace algo obviamente malo debido a eso, el error puede acechar allí, oculto, a veces durante años, hasta que causa Un gran problema.

Resulta que, la mayoría de las veces, las advertencias son una buena idea, después de todo. Incluso los programadores experimentados han aprendido (en realidad, es " especialmente los programadores experimentados que han aprendido") que, en conjunto, las advertencias tienden a hacer más bien que mal. Por cada vez que hizo algo mal deliberadamente y la advertencia fue una molestia, probablemente haya al menos diez veces que hizo algo mal por accidente y la advertencia lo salvó de más problemas. Y la mayoría de las advertencias se pueden deshabilitar o evitar por esas pocas veces en que realmente desea hacer lo "incorrecto".

(Un ejemplo clásico de tal "error" es la prueba if(a = b) . La mayoría de las veces, esto es un error, por lo que la mayoría de los compiladores en estos días lo advierten, algunos incluso por defecto. Pero si realmente quería para asignar b a a y probar el resultado, puede deshabilitar la advertencia escribiendo if((a = b)) .)

La segunda pregunta es, ¿por qué querría pedirle al compilador que trate las advertencias como errores? Diría que es por la naturaleza humana, específicamente, la reacción demasiado fácil de decir "Oh, eso es solo una advertencia, eso no es tan importante, lo limpiaré más tarde". Pero si eres un procrastinador (y no sé sobre ti, pero soy un terrible procrastinador), es fácil posponer la limpieza necesariamente para siempre, y si te acostumbras a ignorar las advertencias, se vuelve más y más fácil perderse un mensaje de advertencia importante que está allí, sin ser notado, en medio de todos los que está ignorando.

Por lo tanto, pedirle al compilador que trate las advertencias como errores es un pequeño truco que puedes jugar para evitar esta debilidad humana.

Personalmente, no soy tan insistente en tratar las advertencias como errores. (De hecho, si soy honesto, puedo decir que prácticamente nunca habilito esas opciones en mi programación "personal"). Pero puede estar seguro de que tengo esa opción habilitada en el trabajo, donde nuestra guía de estilo (que yo escribió) ordena su uso. Y diría, sospecho que la mayoría de los programadores profesionales dirían, que cualquier tienda que no trate las advertencias como errores en C se comporta de manera irresponsable, no se adhiere a las mejores prácticas de la industria comúnmente aceptadas.


Como alguien que trabaja con código C incrustado heredado, habilitar las advertencias del compilador ha ayudado a mostrar muchas debilidades y áreas para investigar al proponer soluciones. En gcc, utilizar -Wall y -Wextra e incluso -Wshadow ha vuelto vital. No voy a ir a todos los peligros, pero enumeraré algunos que han aparecido que ayudaron a mostrar problemas de código.

Variables que quedan atrás

Este puede apuntar fácilmente al trabajo inacabado y las áreas que podrían no estar utilizando todas las variables pasadas, lo que podría ser un problema. Veamos una función simple que puede desencadenar esto:

int foo(int a, int b) { int c = 0; if (a > 0) { return a; } return 0; }

Simplemente compilar esto sin -Wall o -Wextra no devuelve ningún problema. -Wall te dirá que c nunca se usa:

foo.c: En la función ''foo'':

foo.c: 9: 20: advertencia: variable no utilizada ''c'' [-Wunused-variable]

-Wextra también te dirá que tu parámetro b no hace nada:

foo.c: En la función ''foo'':

foo.c: 9: 20: advertencia: variable no utilizada ''c'' [-Wunused-variable]

foo.c: 7: 20: advertencia: parámetro no utilizado ''b'' [-Wunused-parameter] int foo (int a, int b)

Sombreado variable global

Esto fue un poco difícil y no apareció hasta que se usó -Wshadow . Modifiquemos el ejemplo anterior para agregarlo, pero resulta que hay un global con el mismo nombre que un local, lo que causa mucha confusión al intentar usar ambos.

int c = 7; int foo(int a, int b) { int c = a + b; return c; }

Cuando se activó -Wshadow, es fácil detectar este problema.

foo.c: 11: 9: advertencia: la declaración de ''c'' sombrea una declaración global [-Wshadow]

foo.c: 1: 5: nota: la declaración sombreada está aquí

Cadenas de formato

Esto no requiere ningún indicador adicional en gcc, pero aún ha sido la fuente de problemas en el pasado. Una función simple que intenta imprimir datos, pero tiene un error de formato podría verse así:

void foo(const char * str) { printf("str = %d/n", str); }

Esto no imprime la cadena ya que el indicador de formato es incorrecto y gcc felizmente le dirá que esto probablemente no sea lo que quería:

foo.c: En la función ''foo'':

foo.c: 10: 12: advertencia: el formato ''% d'' espera un argumento de tipo ''int'', pero el argumento 2 tiene un tipo ''const char *'' [-Wformat =]

Estas son solo tres de las muchas cosas que el compilador puede verificar por usted. Hay muchos otros como usar una variable no inicializada que otros han señalado.


Definitivamente debe habilitar las advertencias del compilador ya que algunos compiladores son malos para informar algunos errores de programación comunes, incluidos los siguientes:

-> se olvida una inicialización de una variable -> se devuelve un valor de una función se pierde -> los argumentos simples en las familias printf y scanf que no coinciden con la cadena de formato se utiliza una función sin ser declarada de antemano, aunque solo sucede en c

Entonces, como estas funciones se pueden detectar e informar, generalmente no de manera predeterminada; Por lo tanto, esta función debe solicitarse explícitamente mediante las opciones del compilador


El manejo de las advertencias no solo mejora el código, sino que lo convierte en un mejor programador. Las advertencias le informarán sobre cosas que pueden parecerle poco hoy, pero un día ese mal hábito volverá y le morderá la cabeza.

Utilice el tipo correcto, devuelva ese valor, evalúe ese valor de retorno. Tómese el tiempo y reflexione "¿Es realmente el tipo correcto en este contexto?" "¿Necesito devolver esto?" Y la gran cosa; "¿Este código será portátil durante los próximos 10 años?"

Acostúmbrese a escribir código sin advertencia en primer lugar.


Esta es una respuesta específica a C, y por qué esto es mucho más importante para C que para cualquier otra cosa.

#include <stdio.h> int main() { FILE *fp = "some string"; }

Este código se compila con una advertencia . Lo que son y deberían ser errores en casi cualquier otro idioma del planeta (salvo el lenguaje ensamblador) son advertencias en C. Las advertencias en C son casi siempre errores disfrazados. Las advertencias deben ser reparadas, no suprimidas.

Con gcc , hacemos esto como gcc -Wall -Werror .

Esta fue también la razón de la gran indiferencia acerca de algunas advertencias de API no seguras de MS. La mayoría de las personas que programaron C aprendieron la forma difícil de tratar las advertencias como errores y este material parecía que no era el mismo tipo de cosas y quería soluciones no portátiles.


Las advertencias consisten en el mejor consejo que algunos de los desarrolladores de C ++ más hábiles podrían incluir en una aplicación. Vale la pena quedarse con ellos.

C ++, al ser un lenguaje completo de Turing, tiene muchos casos en los que el compilador simplemente debe confiar en que usted sabe lo que está haciendo. Sin embargo, hay muchos casos en los que el compilador puede darse cuenta de que probablemente no tenía la intención de escribir lo que escribió. Un ejemplo clásico son los códigos printf () que no coinciden con los argumentos, o std :: strings pasados ​​a printf (¡eso no me pasa a mí!). En estos casos, el código que escribió no es un error. Es una expresión válida de C ++ con una interpretación válida para que el compilador actúe. Pero el compilador tiene un fuerte presentimiento de que simplemente pasó por alto algo que es fácil de detectar para un compilador moderno. Estas son advertencias. Son cosas que son obvias para un compilador, que utilizan todas las reglas estrictas de C ++ a su disposición, que podría haber pasado por alto.

Desactivar las advertencias, o ignorarlas, es como ignorar los consejos gratuitos de aquellos más hábiles que usted. Es una lección en huberis que termina cuando vuela demasiado cerca del sol y sus alas se derriten, o se produce un error de corrupción de memoria. ¡Entre los dos, tomaré la caída del cielo cualquier día!

"Tratar las advertencias como errores" es la versión extrema de esta filosofía. La idea aquí es que resuelva cada advertencia que le dé el compilador: escuche cada consejo gratuito y actúe en consecuencia. Si este es un buen modelo de desarrollo para usted, depende del equipo y del tipo de producto en el que esté trabajando. Es el enfoque ascético que podría tener un monje. Para algunos, funciona muy bien. Para otros, no.

En muchas de mis aplicaciones no tratamos las advertencias como errores. Hacemos esto porque estas aplicaciones particulares necesitan compilarse en varias plataformas con varios compiladores de diferentes edades. A veces encontramos que en realidad es imposible arreglar una advertencia en un lado sin que se convierta en una advertencia en otra plataforma. Así que simplemente somos cuidadosos. Respetamos las advertencias, pero no nos inclinamos por ellas.


Las advertencias del compilador en C ++ son muy útiles por algunas razones.

1 - Le permite mostrarle dónde puede haber cometido un error que puede afectar el resultado final de sus operaciones. Por ejemplo, si no inicializó una variable o si puso "=" en lugar de "==" (solo hay ejemplos)

2 - Permite también mostrarle dónde su código no se ajusta al estándar de c ++. Es útil porque si el código se ajusta al estándar real, será fácil mover el código a otra plataforma, por ejemplo.

En general, las advertencias son muy útiles para mostrarle dónde tiene errores en su código que pueden afectar el resultado de su algoritmo o evitar algún error cuando el usuario utilizará su programa.


Las otras respuestas son excelentes y no quiero repetir lo que han dicho.

Otro aspecto de "por qué habilitar advertencias" que no se ha tocado correctamente es que ayudan enormemente con el mantenimiento del código. Cuando escribes un programa de gran tamaño, es imposible mantener todo en tu cabeza a la vez. Por lo general, tiene una función o tres en las que está escribiendo y pensando activamente, y tal vez un archivo o tres en su pantalla a los que puede referirse, pero la mayor parte del programa existe en segundo plano en algún lugar y debe confiar en que sigue trabajando

Tener advertencias y tenerlas tan enérgicas y en la cara como sea posible ayuda a alertarlo si algo que cambia crea problemas para algo que no puede ver.

Tomemos, por ejemplo, la advertencia de -Wswitch-enum . Eso activa una advertencia si usa un interruptor en una enumeración y omite uno de los posibles valores de enumeración. Es algo que podría pensar que sería un error improbable: probablemente al menos miró la lista de valores de enumeración cuando escribió la declaración de cambio. Incluso podría tener un IDE que generara las opciones de cambio para usted, sin dejar espacio para errores humanos.

Esta advertencia realmente se hace realidad cuando, seis meses después, agrega otra posible entrada a la enumeración. Nuevamente, si está pensando en el código en cuestión, probablemente estará bien. Pero si esta enumeración se usa para múltiples propósitos diferentes y es para uno de los que necesita la opción adicional, es muy fácil olvidarse de actualizar un interruptor en un archivo que no ha tocado durante 6 meses.

Puedes pensar en las advertencias de la misma manera que pensarías en los casos de prueba automatizados: te ayudan a asegurarte de que el código sea sensible y a hacer lo que necesitas cuando lo escribes por primera vez, pero ayudan aún más para asegurarte de que sigue haciendo lo que necesitas mientras lo presionas. La diferencia es que los casos de prueba funcionan de manera muy limitada a los requisitos de su código y usted tiene que escribirlos, mientras que las advertencias funcionan ampliamente con estándares razonables para casi todo el código, y son generosamente suministrados por los ataúdes que hacen los compiladores.


Siempre debe habilitar las advertencias del compilador porque el compilador a menudo puede decirle qué tiene de malo su código. Para hacer esto, pasa -Wall -Wextra al compilador.

Por lo general, debe tratar las advertencias como errores porque a menudo las advertencias generalmente significan que hay algo mal con su código. Sin embargo, a menudo es muy fácil ignorar estos errores. Por lo tanto, tratarlos como errores hará que la compilación falle, por lo que no puede ignorar los errores. Para tratar las advertencias como errores, pase -Werror al compilador.


Tómelo con calma: no tiene que hacerlo, no es necesario. -Wall y -Werror fue diseñado por maníacos que refactorizan el código por sí mismos: fue inventado por los desarrolladores del compilador para evitar romper las compilaciones existentes después de la actualización del compilador en el lado del usuario . Más tarde, las personas que odian cuando otros rompen su código también lo encontraron útil. La característica no es nada, sino todo sobre la decisión de romper o no romper la compilación.

Por lo tanto, depende totalmente de su preferencia usarlo o no. Lo uso todo el tiempo porque me ayuda a corregir mis errores.


Tratar las advertencias como errores es solo un medio de autodisciplina: estaba compilando un programa para probar esa nueva característica brillante, pero no puede hasta que arregle las partes descuidadas. No hay información adicional que Werror proporcione, solo establece prioridades muy claramente:

No agregue código nuevo hasta que solucione problemas en el código existente

Lo importante es la mentalidad, no las herramientas. La salida de diagnóstico del compilador es una herramienta. MISRA (para C incrustado) es otra herramienta. No importa cuál use, pero podría decirse que las advertencias del compilador son la herramienta más fácil que puede obtener (es solo un indicador para configurar) y la relación señal / ruido es muy alta. Entonces no hay razón para no usarlo.

Ninguna herramienta es infalible. Si escribe const float pi = 3.14; , ninguna herramienta le dirá que definió π con mala precisión, lo que puede ocasionar problemas en el futuro. La mayoría de las herramientas no sorprenderán if(tmp < 42) , incluso si se sabe comúnmente que dar nombres sin sentido a las variables y usar números mágicos es una forma de desastre en grandes proyectos. Debe comprender que cualquier código de "prueba rápida" que escriba es solo eso: una prueba, y debe hacerlo correctamente antes de pasar a otras tareas, mientras aún ve sus defectos. Si deja esos códigos como están, la depuración si después de pasar dos meses agregando nuevas funciones será significativamente más difícil.

Una vez que entras en la mentalidad correcta, no tiene sentido usar Werror . Tener advertencias como advertencias le permitirá tomar una decisión informada sobre si aún tiene sentido ejecutar la sesión de depuración que estaba a punto de comenzar, o cancelarla y corregir las advertencias primero.