¿Por qué debería habilitar siempre las advertencias del compilador?
A menudo escucho que al compilar programas C y C++ debo "activar siempre las advertencias del compilador". ¿Por qué es esto necesario? ¿Cómo puedo hacer eso?
A veces también escucho que debería "tratar las advertencias como errores". ¿Debería? ¿Cómo puedo hacer eso?
¿Por qué debería habilitar las advertencias?
Los compiladores de C y C++ son notoriamente malos a la hora de informar de forma predeterminada algunos errores comunes del programador , como por ejemplo:
- olvidar inicializar una variable
- olvidar
return
un valor de una función - argumentos
printf
yscanf
familias que no coinciden con la cadena de formato - se utiliza una función sin haber sido declarada de antemano (solo C)
Estos pueden detectarse e informarse, aunque normalmente no de forma predeterminada; esta característica debe solicitarse explícitamente a través de las opciones del compilador.
¿Cómo puedo habilitar las advertencias?
Esto depende de su compilador.
Los compiladores de Microsoft C y C++ comprenden modificadores como /W1
, /W2
, y . Usa al menos . y puede 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./W3
/W4
/Wall
/W3
/W4
/Wall
La mayoría de los demás compiladores entienden opciones -Wall
como -Wpedantic
y -Wextra
. -Wall
es imprescindible y el resto son recomendables (tenga en cuenta que, a pesar de su nombre, -Wall
sólo habilita las advertencias más importantes, no todas ). Estas opciones se pueden utilizar por separado o todas juntas.
Es posible que su IDE tenga una manera de habilitarlos desde la interfaz de usuario.
¿Por qué debería tratar las advertencias como errores? ¡Son sólo advertencias!
Una advertencia del compilador indica un problema potencialmente grave en su código. Los problemas enumerados anteriormente casi siempre son fatales; otros pueden serlo o no, 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, solucione el problema, es decir, utilice una característica o construcción de lenguaje diferente para que la advertencia ya no se active. Si esto resulta muy difícil, desactive esa advertencia en particular caso por caso.
No desea simplemente dejar las 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. Cualquier cosa más y es fácil que una nueva advertencia se pierda en una avalancha 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 de programas. Si está lanzando su proyecto al mundo en el formato fuente, entonces podría ser una buena idea no proporcionar -Werror
un equivalente en el script de compilación publicado . Las personas podrían intentar construir su proyecto con una versión diferente del compilador, o con un compilador completamente diferente, que puede tener un conjunto diferente de advertencias habilitadas. Es posible que desee que su construcción tenga éxito. Sigue siendo una buena idea mantener las advertencias habilitadas, para que las personas que vean mensajes de advertencia puedan enviarle informes de errores o parches.
¿Cómo puedo tratar las advertencias como errores?
Esto se hace nuevamente con 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 produce alguna advertencia.
¿Es suficiente?
¡Probablemente no! A medida que aumenta su nivel de optimización, el compilador comienza a observar el código cada vez más de cerca, y este escrutinio más detenido puede revelar más errores. Por lo tanto, no se contente con los interruptores de advertencia por sí solos, utilícelos siempre al compilar con las optimizaciones habilitadas ( -O2
o -O3
, o /O2
si usa MSVC).
C es, como es sabido, un lenguaje de nivel bastante bajo en lo que respecta a los HLL . C++, aunque pueda parecer un lenguaje de nivel considerablemente más alto que C, todavía comparte varios de sus rasgos. Y una de esas características es que los lenguajes fueron diseñados por programadores, para programadores y, específicamente, programadores que sabían lo que estaban haciendo.
(Durante el resto de esta respuesta me centraré en C. La mayor parte de lo que diré también se aplica a C++, aunque tal vez no con tanta fuerza. Aunque, como dijo Bjarne Stroustrup , " C hace que sea fácil dispararse a uno mismo". en el pie; C++ lo hace más difícil, pero cuando lo haces te vuela toda la pierna " . .)
Si sabes lo que estás haciendo, si realmente sabes lo que estás haciendo, a veces tendrás que "romper las reglas". Pero la mayor parte del tiempo, 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 sin sentido todo el tiempo es una mala idea.
Pero en C y C++, hay un número sorprendentemente grande de cosas que puedes hacer que son "malas ideas", pero que formalmente no están "en contra de las reglas". A veces son una mala idea en algunas ocasiones (pero pueden ser defendibles en otras ocasiones); a veces son una mala idea prácticamente todo el tiempo. Pero la tradición siempre ha sido no advertir sobre estas cosas, porque, nuevamente, se supone que los programadores saben lo que están haciendo, no harían estas cosas sin una buena razón y se molestarían por un montón de cosas. de advertencias innecesarias.
Pero, por supuesto, no todos los programadores saben realmente lo que están haciendo. Y, en particular, todo programador de C (sin importar su experiencia) pasa por una fase de ser un programador principiante de C. E incluso los programadores experimentados en C pueden descuidarse y cometer errores.
Finalmente, la experiencia ha demostrado no sólo que los programadores cometen errores, sino que estos errores pueden tener consecuencias reales y graves. Si comete un error y el compilador no le avisa, y de alguna manera el programa no falla inmediatamente o no hace algo obviamente incorrecto a causa de ello, el error puede acechar allí, oculto, a veces durante años, hasta causar un problema realmente grande.
Resulta que, la mayoría de las veces, las advertencias son una buena idea, después de todo. Incluso los programadores experimentados han aprendido eso (en realidad, es " especialmente los programadores experimentados lo han aprendido"), en general, las advertencias tienden a hacer más bien que mal. Por cada vez que hiciste algo mal deliberadamente y la advertencia fue una molestia, probablemente hay al menos diez veces que hiciste algo mal por accidente y la advertencia te salvó de más problemas. Y la mayoría de las advertencias se pueden desactivar o solucionar en esas pocas ocasiones en las que realmente desea hacer algo "incorrecto".
(Un ejemplo clásico de tal "error" es la prueba if(a = b)
. La mayoría de las veces, esto es realmente un error, por lo que la mayoría de los compiladores hoy en día advierten sobre ello, algunos incluso de forma predeterminada. Pero si realmente desea asignar y probar el resultado, puede desactivar la advertencia escribiendo .)b
a
if((a = b))
La segunda pregunta es, ¿por qué querrías pedirle al compilador que trate las advertencias como errores? Yo diría que se debe a la naturaleza humana, específicamente, a la reacción tan fácil de decir "Oh, eso es sólo una advertencia, eso no es tan importante, lo limpiaré más tarde". Pero si eres un procrastinador (y no sé tú, pero yo soy un procrastinador de clase mundial), es fácil posponer la limpieza necesaria para siempre, y si adquieres el hábito de ignorar las advertencias, Cada vez es más fácil pasar por alto un mensaje de advertencia importante que está allí, desapercibido, en medio de todos los que estás ignorando implacablemente.
Entonces, pedirle al compilador que trate las advertencias como errores es un pequeño truco que puede jugar usted mismo para sortear esta debilidad humana, para obligarse a corregir las advertencias hoy , porque de lo contrario su programa no se compilará.
Personalmente, no soy tan insistente en tratar las advertencias como errores; de hecho, si soy honesto, puedo decir que no tiendo a habilitar esa opción en mi programación "personal". Pero puedes estar seguro de que tengo esa opción habilitada en el trabajo, donde nuestra guía de estilo (que escribí) exige su uso. Y yo diría (sospecho que dirían la mayoría de los programadores profesionales) que cualquier taller que no trate las advertencias como errores en C se está comportando de manera irresponsable, no se está adhiriendo a las mejores prácticas comúnmente aceptadas en la industria.
Las advertencias consisten en los mejores consejos que algunos de los desarrolladores de C++ más hábiles podrían incorporar a una aplicación. Vale la pena conservarlos.
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 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 (¡aunque eso nunca me pase a mí!). En estos casos, el código que escribiste no es un error. Es una expresión C++ válida con una interpretación válida para que actúe el compilador. Pero el compilador tiene el fuerte presentimiento de que usted 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 utiliza todas las reglas estrictas de C++ a su disposición, y que quizás usted haya pasado por alto.
Desactivar las advertencias o ignorarlas es como optar por ignorar los consejos gratuitos de personas más hábiles que usted. Es una lección de arrogancia que termina cuando vuelas demasiado cerca del sol y tus alas se derriten o cuando ocurre un error de corrupción de memoria. ¡Entre los dos, aceptaré caer del cielo cualquier día!
"Treat warnings as errors" is the extreme version of this philosophy. The idea here is that you resolve every warning the compiler gives you -- you listen to every bit of free advice and act on it. Whether this is a good model for development for you depends on the team and what kind of product you are working on. It's the ascetic approach that a monk might have. For some, it works great. For others, it does not.
On many of my applications we do not treat warnings as errors. We do this because these particular applications need to compile on several platforms with several compilers of varying ages. Sometimes we find it is actually impossible to fix a warning on one side without it turning into a warning on another platform. So we are merely careful. We respect warnings, but we don't bend over backwards for them.