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

302

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?

norte. 'pronombres' m.
fuente

Respuestas:

341

¿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 returnun valor de una función
  • argumentos printfy scanffamilias 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.

Microsoft C y C ++ compiladores entienden como interruptores /W1, /W2, /W3, /W4y /Wall. Usar al menos /W3. /W4y /Wallpuede 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, -Wpedanticy -Wextra. -Walles esencial y se recomienda todo lo demás (tenga en cuenta que, a pesar de su nombre, -Wallsolo 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, evite esto, 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 el formulario fuente, entonces podría ser una buena idea no suministrar -Werroro 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. Sigue siendo una buena idea mantener las advertencias habilitadas, para que las personas que ven los 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. /WXes para Microsoft, la mayoría de los demás lo usan -Werror. En cualquier caso, la compilación fallará si se producen advertencias.

norte. 'pronombres' m.
fuente
107
He publicado estas preguntas y respuestas porque estoy cansado de decirle a la gente que habilite las advertencias. Ahora puedo señalarlos aquí (o, si estoy de mal humor, cerrar su pregunta como un tonto). ¡Puede mejorar esta respuesta o agregar la suya!
n. 'pronombres' m.
16
También puedes usar clang's -Weverything
pmg
99
El único modificador que agregaría es que algunas advertencias pueden no ser útiles para su aplicación. (He visto advertencias de que el compilador agregó 2 bytes de relleno entre elementos en una estructura. La aplicación era para la creación de prototipos, por lo que un poco de memoria desperdiciada no nos molestó). Trate todas las advertencias como errores y luego solo desactive una advertencia si sabes por qué esa advertencia no te ayudará.
Kyle A
20
La desventaja de tratar las advertencias como errores para las personas que siguen sus instrucciones de compilación predeterminadas es que su código se pudre a medida que los compiladores agregan nuevas advertencias. Es posible que los usuarios que descarguen su código e intenten construirlo en el futuro no puedan hacerlo, porque su compilador es demasiado nuevo y emite una advertencia sobre algunos paréntesis adicionales o algo que a su compilador no le importaba. El usuario que encuentra el error no es responsable de su código o su sistema de compilación, y no tiene idea de cómo desactivar el tratamiento de las advertencias como errores y, de hecho, construir su proyecto.
interfecto
15
@interfect Sí, esto me pasó un par de veces. No es problema. Si elige construir un software sin mantenimiento utilizando un compilador con el que nunca se probó, bueno, es mejor que esté preparado para realizar algún mantenimiento usted mismo.
n. 'pronombres' m.
94

C es, famoso, un lenguaje de bajo nivel a medida que avanzan las HLL. C ++, aunque podría parecer un lenguaje de nivel considerablemente más alto que C, aún 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 una cantidad 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, una vez más, 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 principiante. 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 incorrecto debido a eso, el error puede acechar allí, oculto, a veces durante años, hasta que causa un muy 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, " especialmente los programadores experimentados han aprendido") que, en general, las advertencias tienden a hacer más bien que mal. Por cada vez que hizo algo mal deliberadamente y la advertencia fue una molestia, es probable que 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)mayor parte del tiempo, esto es un error, por lo que la mayoría de los compiladores de estos días advierten sobre ella -.. Algunos incluso por defecto, pero si realmente quería tanto asignar ba ay la prueba Como 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? Yo 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, es cada vez más fácil perderse un importante mensaje de advertencia que está ahí, 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 sincero, puedo decir que prácticamente nunca habilito esa opción 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.

Steve Summit
fuente
99
"programadores que sabían lo que estaban haciendo" - LOL; hay una falacia de "no hay verdadero escocés" si alguna vez la veo :)
Dancrumb
3
@Dancrumb LOL de vuelta atcha. Nunca estoy seguro de entender la falacia de No verdadero escocés , pero me gusta, así que este será un buen ejercicio para mí. Supongo que la aplicación aquí es así: "Ningún programador de C escribiría nunca if(a = b), por lo tanto, no tenemos que advertir al respecto". (Luego, alguien produce una lista de 10 errores críticos en 10 productos lanzados que son el resultado de este error en particular). "Está bien, ningún programador de C experimentado escribiría eso ..."
Steve Summit
3
@SteveSummit pero un programador de C realmente experimentado puede escribir if (returnCodeFromFoo = foo(bar))y decirlo en serio, para capturar y probar el código en un solo lugar (¡Suponga que el único propósito fooes tener efectos secundarios!) El hecho de que un programador realmente experimentado pueda saber que esto no es un problema un buen estilo de codificación no viene al caso;)
alephzero
55
La cuestión es que la mayoría de los programadores con mucha experiencia habilitan la mayoría, si no todas, las advertencias. Si quieren usar algo como if (returnCodeFromFoo = foo(bar)), entonces ponen un comentario y apagan la advertencia (para que cuando el programador de mantenimiento lo vea 4 años después, se dé cuenta de que el código es intencional. Dicho esto, trabajé con alguien que (en Microsoft C ++ land) insistió en que combinar / Wall con el tratamiento de las advertencias como errores era el camino a seguir. Uh, no lo es (a menos que desee poner muchos comentarios de supresión).
Flydog57
3
Como alguien que no escribe código a diario, pero cuando lo hago tiende a ser de metal desnudo (a menudo en un tablero de mi propio diseño), encuentro advertencias invaluables. Cuando se introducen valores en registros internos (para una ubicación del descriptor DMA es un ejemplo), la advertencia sobre la conversión a puntero significa que realizo una conversión para borrar la advertencia. No sería un error, pero si alguien más (¡o incluso yo mismo!) Recoge ese código en unos meses, podría ser confuso. Además, aplico la regla de no presentar advertencias a las salidas de mis herramientas CAD también.
Peter Smith
39

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.

Cort Ammon
fuente
11
Lo que tiene C ++ siendo Turing completo tiene que ver con eso. Muchos idiomas están completos y no confían en ti si haces algo mal ...
Adiós SE
3
@KamiKaze cada idioma tendrá errores idiomáticos (por ejemplo, Java no puede evitar que escribas un equals/ inconsistente hashCode), y es un problema de calidad de implementación cuáles de los que se informan.
Caleth
2
@KamiKaze El bit de integridad de Turing viene a mostrar que hay casos en los que el compilador no puede probar que su código no funcionará según lo planeado. Esto es importante porque los compiladores no pueden hacer que todo el código "incorrecto" sea un error. Los errores solo se pueden reservar para los comportamientos que los diseñadores de idiomas están seguros de que siempre serán "incorrectos". (generalmente porque conduce por caminos que son inconsistentes).
Cort Ammon
2
Lo que también apunta al desafío con "todas las advertencias son errores". Las advertencias son, por diseño, más oportunistas, activando un código potencialmente correcto a cambio de activar un código incorrecto con más frecuencia. Las advertencias como errores conducen a que no pueda ejercer todas las capacidades del lenguaje.
Cort Ammon
2
Sin embargo, en general, los programadores quieren un lenguaje que haga más que algo "seguro". Queremos un lenguaje que haga lo que pensamos que le dijimos que hiciera. Por lo tanto, las advertencias siguen siendo importantes porque la clase real de cosas que queremos que haga la computadora es una clase semántica. El compilador puede elegirlo definiendo "incorrecto" o "inseguro", pero al final todavía tiene una superclase de los comportamientos que el programador quería que el programa hiciera. Las advertencias ayudan a reducir esa superclase.
Cort Ammon
19

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.

Use 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.

RedSonja
fuente
17

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 sonido metálico -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 aparece 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.

Puede pensar en las advertencias de la misma manera que pensaría en los casos de prueba automatizados: le ayudan a asegurarse de que el código sea sensible y a hacer lo que necesita cuando lo escribe por primera vez, pero ayudan aún más para asegurarse de que sigue haciendo lo que necesitas mientras lo presionas. La diferencia es que los casos de prueba funcionan de manera muy estricta según 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.

Josiah
fuente
99
La otra forma en que ayudan con el mantenimiento es cuando está mirando el código de otra persona y no puede saber si un efecto secundario fue intencional. Con las advertencias, sabes que al menos estaban al tanto del problema.
Robin Bennett
O, en mi caso, importa un archivo de un sistema integrado que contiene una declaración de cambio de línea de más de 3000 sobre una enumeración con varios miles de valores. Las advertencias de "falla" (evitadas mediante el uso de goto) enmascararon una serie de errores "no manejados" ... el compilador incorporado no emitió ninguno de esos, pero los errores fueron importantes.
Más el
15

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 sucedió iy strdentro de esa cantidad colosal de código por allá ...

Hasta que, un día, se encontraron en la situación en la que descubrieron que idxse usa sin inicializar, por lo que 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!

gsamaras
fuente
44
A su título: no necesariamente. Por ejemplo, una advertencia que sugiere utilizar paréntesis en una fórmula que realmente no los necesita apunta a un problema que nunca causará un error. Las precedentes del operador en un lenguaje de programación dado no cambian. Nunca.
Marc van Leeuwen
44
@MarcvanLeeuwen La instancia que cita puede convertirse en un error, por ejemplo, si el programador que no recuerda la precedencia del operador modifica un poco la fórmula correctamente. La advertencia le dice: "puede que no esté claro para alguien en algún momento, agregue algunos paréntesis para que quede más claro". Aunque uno debe estar de acuerdo en que el título de la publicación original no siempre es cierto.
Hubert Jasieniecki
^ Cualquier cosa puede convertirse en un error. Es tan fácil introducir un error en el código parcialmente entre paréntesis como en el código completamente entre paréntesis.
Jim Balter
... Dicho sea de paso, no tengo preguntas para el depurador cuya reacción primero en "Oh, es segfaulted de str[idx]" no es "Muy bien, ¿dónde están stry idxdefine`?
Justin Time - Restablecer Mónica
2
Tienes suerte si tienes una falla de segmentación. Si tiene menos suerte, es posible que por casualidad idxsea ​​el valor que esperaba en su prueba (no muy improbable si el valor esperado es 0), y en realidad apunte a algunos datos confidenciales que nunca deberían imprimirse cuando se implementan.
celtschk
14

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 se Werrorproporciona información adicional , 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;, la mayoría de las herramientas no le dirán que definió π con una 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 características será significativamente más difícil.

Una vez que entras en la mentalidad correcta, no tiene sentido usarla 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.

Dmitry Grigoryev
fuente
3
Para bien o para mal, la clippyherramienta de revestimiento para Rust en realidad advertirá sobre la constante "3.14". En realidad es un ejemplo en los documentos . Pero como se puede adivinar por el nombre, clippyse enorgullece de ser agresivamente útil.
emk
1
@emk Gracias por este ejemplo, tal vez debería reformular mi respuesta de una manera que nunca diga "nunca" . No quise decir que la comprobación de valores π imprecisos es imposible, solo que deshacerse de las advertencias no garantiza una calidad de código decente.
Dmitry Grigoryev
Una de las advertencias que le dan los errores es que las compilaciones automatizadas fallarán, lo que le alertará de que algo salió mal. Las construcciones automatizadas también permiten automatizar el revestimiento (la explosión es 3 ... 2 ... 1 .. :)
Móż
8

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 utilizando -Walle -Wextrae incluso se -Wshadowha convertido en 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 a un trabajo inacabado y á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 eso cnunca 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 es un poco difícil y no apareció hasta que -Wshadowse usó. 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.

Dom
fuente
77
En el mundo incrustado, las advertencias que más me preocupan son " possible loss of precision" y " comparison between signed and unsigned" advertencias. Me resulta difícil captar la cantidad de "programadores" ignoran estos (de hecho, no estoy realmente seguro de por qué no son errores)
MAWG dice Restablecer Mónica
3
En el último caso, @Mawg, creo que la razón principal por la que no es un error es que el resultado de sizeofno está firmado, pero el tipo entero predeterminado está firmado. El sizeoftipo de resultado size_t, se usa típicamente para cualquier cosa relacionada con el tamaño de tipo, como, por ejemplo, alineación o recuento de elementos de matriz / contenedor, mientras que los enteros en general están destinados a usarse como "a intmenos que se requiera lo contrario". Teniendo en cuenta cuántas personas se les enseña a usar intpara iterar sobre sus contenedores (en comparación intcon size_t), hacer que sea un error rompería casi todo. ; P
Justin Time - Restablece a Monica el
6

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 esto parecía que no era el mismo tipo de cosas y quería soluciones no portátiles.

Joshua
fuente
5

LAS ADVERTENCIAS DEL COMPILADOR SON SU AMIGO (no gritar, mayúsculas para enfatizar).

Trabajo en sistemas Fortran-77 heredados. El compilador me dice cosas valiosas: no coinciden los tipos de datos de argumentos en una llamada de subrutina, usando una variable local antes de que se haya establecido un valor en la variable, si tengo un argumento de variable o subrutina que no se usa. Estos son casi siempre errores.

Evitar una publicación larga: cuando mi código se compila limpiamente, el 97% funciona. El otro tipo con el que trabajo compila con todas las advertencias apagadas, pasa horas o días en el depurador y luego me pide ayuda. Acabo de compilar su código con las advertencias y le digo qué arreglar.

Mark Diaz
fuente
5

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 -Wextraal compilador.

Por lo general, debe tratar las advertencias como errores porque 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 -Werroral compilador.

SS Anne
fuente
4

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.

Fizik26
fuente
4

Ignorar las advertencias significa que dejó un código descuidado que no solo podría causar problemas en el futuro para otra persona, sino que también hará que los mensajes de compilación importantes sean menos notados por usted. Cuanto mayor sea la salida del compilador, menos se notará o se molestará. Más limpio, mejor. También significa que sabes lo que estás haciendo. Las advertencias son muy poco profesionales, descuidadas y riesgosas.

Kirk Augustin
fuente
4

Una vez trabajé para una gran empresa (Fortune 50) que fabricaba equipos de prueba electrónicos.

El producto principal de mi grupo fue un programa MFC que, con el paso de los años, generó literalmente cientos de advertencias. Que fueron ignorados en casi todos los casos.

Esta es una pesadilla cuando se producen errores.

Después de esa posición, tuve la suerte de ser contratado como el primer desarrollador en una nueva startup.

Alenté una política de 'no advertencia' para todas las compilaciones, con niveles de advertencia del compilador configurados para ser bastante ruidosos.

Nuestra práctica era usar la advertencia #pragma: pulsar / deshabilitar / pop para el código que el desarrollador estaba seguro de que estaba realmente bien, junto con una declaración de registro en el nivel de depuración, por si acaso.

Esta práctica funcionó bien para nosotros.

Jim en Texas
fuente
1
Secundado #pragma warningno solo suprime las advertencias, tiene el doble propósito de comunicar rápidamente a otros programadores que algo es intencional y no accidental, y actúa como una etiqueta de búsqueda para localizar rápidamente áreas potencialmente problemáticas cuando algo se rompe, pero corregir los errores / advertencias no arreglalo.
Justin Time - Restablece a Monica el
Tienes razón Justin, así es exactamente como vi la advertencia #pragma
Jim In Texas
3

Una advertencia es un error esperando a suceder. Por lo tanto, debe habilitar las advertencias del compilador y ordenar su código para eliminar cualquier advertencia.

josyb
fuente
3

Solo hay un problema al tratar las advertencias como errores: cuando usa código proveniente de otras fuentes (por ejemplo, bibliotecas micro $ ** t, proyectos de código abierto), no hicieron su trabajo correctamente y compilar su código genera toneladas de advertencias.

Yo siempre escribo mi código por lo que no genera las advertencias o errores, y limpiaré hasta que se compila sin generar ningún ruido extraño. La basura con la que tengo que trabajar me asombra, y me sorprende cuando tengo que construir un gran proyecto y ver pasar una corriente de advertencias donde la compilación solo debe anunciar qué archivos procesó.

También documento mi código porque sé que el costo real de por vida del software proviene principalmente del mantenimiento, no de escribirlo inicialmente, pero esa es una historia diferente ...

FKEinternet
fuente
No lo golpee, hay buen dinero en el trabajo de consultoría para personas que pueden leer las advertencias del compilador en voz alta a los clientes.
Más
El código de otras fuentes que generan advertencias no necesariamente significa que los autores fueron descuidados. También puede significar que compilaron el código con un compilador diferente que generó un conjunto diferente de advertencias. El código puede compilarse sin advertencias en un compilador y generar advertencias en otro. O tal vez es solo un conjunto diferente de opciones de advertencia; por ejemplo, ellos usan -Wally tú los usas -Wall -Wextra.
celtschk
2

Alguna advertencia puede significar un posible error semántico en el código o una posible UB. Por ejemplo , ;después if(), variable no utilizada, variable global enmascarada por local, o comparación de firmado y sin signo. 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.

Swift - Friday Pie
fuente
1

El hecho de que los compiladores de C ++ aceptan compilar código que obviamente da como resultado un comportamiento indefinido en absoluto es un defecto importante en los compiladores. La razón por la que no solucionan esto es porque hacerlo probablemente rompería algunas compilaciones utilizables.

La mayoría de las advertencias deben ser errores fatales que impiden que se complete la compilación. Los valores predeterminados para mostrar solo los errores y realizar la compilación de todos modos son incorrectos y si no los anula para tratar las advertencias como errores y dejar algunas advertencias, es probable que su programa falle y haga cosas al azar.

Jason Livesay
fuente
Irónicamente, una gran cantidad de comportamiento indefinido en realidad no causa advertencias, pero en silencio se compila perfectamente en una pequeña bomba de tiempo desagradable. ; P
Justin Time - Restablece a Monica el
1
El problema es que si el estándar exige un mensaje de error, ese mensaje de error debe emitirse en todos los casos en que se produce el problema, pero nunca si el problema no se produce. Pero en casos como el comportamiento indefinido, eso puede ser imposible de decidir. Por ejemplo, considere el siguiente código: int i; if (fun1()) i=2; if (fun2()) i=3; char s="abcde"[i];este código exhibe un comportamiento indefinido si y solo si ambos fun1()y fun2()pueden regresar falseen la misma ejecución de la función. ¿Qué puede ser cierto o no, pero cómo debe decirlo el compilador?
celtschk
-2

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

-> se olvida la inicialización de una variable -> se pierde un valor de una función -> 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 característica debe solicitarse explícitamente a través de las opciones del compilador.

Hasan Raza
fuente
-32

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 para sí mismos: fue inventado por los desarrolladores del compilador para evitar romper las compilaciones existentes después de las actualizaciones del compilador en el lado del usuario . La característica no es nada, sino todo sobre la decisión de romper o no romper la compilación.

Es totalmente de su preferencia usarlo o no. Lo uso todo el tiempo porque me ayuda a corregir mis errores.

sqr163
fuente
19
Aunque no es obligatorio , es muy recomendable usarlos
Spikatrix
18
-Wall and -Werror was designed by code-refactoring maniacs for themselves.[cita requerida]
YSC
22
Parece que te estás contradiciendo a ti mismo. Si "lo usa todo el tiempo porque ayuda a corregir [sus] errores", ¿no vale la pena enseñar a los programadores más nuevos para que lo hagan en todas partes desde el principio? No creo que esta pregunta está preguntando si es o no es posible compilar sin -Wally -Werror, sólo está preguntando si es una idea buena. Lo cual, desde tu última oración, parece que estás diciendo que lo es.
scohe001
12
Cuando tenga más experiencia en el mantenimiento de código no escrito por usted, revise esta respuesta.
Thorbjørn Ravn Andersen
Esta no es una respuesta útil. Hay 4 signos de interrogación en la pregunta de los OP. ¿Cuántas responde esta respuesta?
Anders