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 debería "tratar las advertencias como errores". ¿Debería? ¿Cómo puedo hacer eso?
Los compiladores de C y C++ son notoriamente malos para informar algunos errores comunes de los programadores de forma predeterminada , como:
return un valor de una funciónprintf y scanf que no coinciden con la cadena de formatoEstos pueden ser detectados e informados, pero por lo general no por defecto; esta característica debe solicitarse explícitamente a través de las opciones del compilador.
Esto depende de su compilador.
Los compiladores de Microsoft C y C++ comprenden 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 sin problemas 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 imprescindible y todos los demás recomendados (nótese que, a pesar de su nombre, -Wall solo activa los avisos más importantes, no todos ). Estas opciones se pueden utilizar por separado o todas juntas.
Su IDE puede tener una forma de habilitarlos desde la interfaz de usuario.
Una advertencia del compilador señala 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, solucione el problema, es decir, use una función o construcción de lenguaje 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 las advertencias como advertencias, incluso si todas ellas son falsas alarmas. Podría estar bien para proyectos muy pequeños en los que 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 avalancha de viejas y familiares. No permitas eso. Solo haz que todo tu 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 podría ser una buena idea no proporcionar -Werror o equivalente en su script de compilación publicado . Las personas pueden intentar compilar 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, para que las personas que vean mensajes de advertencia puedan enviarle informes de errores o parches.
Esto se hace de nuevo con conmutadores de 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.
¡Probablemente no! A medida que aumenta su nivel de optimización, el compilador comienza a mirar el código cada vez más de cerca, y este escrutinio más detallado puede revelar más errores. Por lo tanto, no se conforme con los interruptores de advertencia por sí mismos, utilícelos siempre al compilar con optimizaciones habilitadas ( -O2 o -O3 , o /O2 si usa MSVC).
C es, como se sabe, un lenguaje de bajo nivel en lo que respecta a los HLL . C++, aunque puede parecer un lenguaje de nivel considerablemente más alto que C, aún comparte varias de sus características. 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.
(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 sea fácil pegarse un tiro a uno mismo en el pie; C++ lo hace más difícil, pero cuando lo haces te vuela 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 deliberadamente 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, se supone que los programadores saben lo que están haciendo, no estarían haciendo estas cosas sin una buena razón, y estarían molestos por un montón de advertencias innecesarias.
Pero, por supuesto, no todos los programadores saben realmente lo que están haciendo. Y, en particular, cada programador de C (no importa cuán experimentado sea) pasa por una fase de ser un programador de C principiante. E incluso los programadores de C experimentados 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 falla de inmediato o hace algo obviamente incorrecto debido a ello, el error puede acechar allí, oculto, a veces durante años, hasta que causa un problema realmente grande.
Entonces 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 han aprendido eso"), 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, 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 modificar para esas pocas veces en las 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 realmente un error, por lo que la mayoría de los compiladores en estos días advierten al respecto, algunos incluso de manera predeterminada. Pero si realmente desea para asignar b a a y probar el resultado, puede desactivar 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 arreglaré 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 básicamente para siempre, y si te acostumbras a ignorar las advertencias, cada vez es más fácil pasar por alto un importante mensaje de advertencia que está ahí, desapercibido, en medio de todos los que está ignorando implacablemente.
Por lo tanto, pedirle al compilador que trate las advertencias como errores es un pequeño truco que puede jugar consigo 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 suelo habilitar 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 escribí) exige su uso. Y yo 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 está comportando de manera irresponsable, no se adhiere a las mejores prácticas de la industria comúnmente aceptadas.
Algunas advertencias pueden significar un posible error semántico en el código o una posible UB . Por ejemplo ; después de if() , una variable no utilizada, una variable global enmascarada por local o una comparación de firmada y no firmada. Muchas advertencias están relacionadas con el analizador de código estático en el compilador o con 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 comandos para activar el modo de "advertencias como errores". Es una herramienta agradable, aunque cruel, para educar a los programadores novatos.
Tómatelo con calma: no tienes que hacerlo, no es necesario. -Wall y -Werror fueron diseñados por maníacos de refactorización de código para ellos mismos: fue inventado por desarrolladores de compiladores para evitar romper las compilaciones existentes después de las actualizaciones del compilador o del lenguaje de programación en el lado del usuario . La función no es nada, sino que se trata de la decisión de romper o no romper la compilación.
Depende totalmente de su preferencia usarlo o no. Lo uso todo el tiempo porque me ayuda a corregir mis errores.
Las advertencias consisten en los mejores consejos que algunos de los desarrolladores de C++ más expertos podrían incluir en una aplicación. Vale la pena tenerlos cerca.
C ++, al ser un lenguaje completo de Turing , tiene muchos casos en los que el compilador simplemente debe confiar en que sabía lo que estaba 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 (¡no es que eso me pase nunca!). 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 actúe el compilador. 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, usando todas las reglas estrictas de C++ a su disposición, que podría haber pasado por alto.
Desactivar las advertencias o ignorarlas es como elegir 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, tomaré caer 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 todas las advertencias que le da el compilador: escuche todos los consejos gratuitos y actúe en consecuencia. Que este sea 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 distintas edades. A veces nos encontramos con que es realmente imposible corregir 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 hacemos lo imposible por ellas.
El manejo de las advertencias no solo mejora el código, sino que lo convierte a usted en un mejor programador. Las advertencias te hablarán de cosas que hoy te pueden parecer pequeñas, pero que algún día esa mala costumbre volverá y te arrancará la cabeza de un mordisco.
Use el tipo correcto, devuelva ese valor, evalúe ese valor de retorno. Tómese su tiempo y reflexione "¿Es este realmente el tipo correcto en este contexto?" "¿Tengo que devolver esto?" Y el grande; "¿Este código será portátil durante los próximos 10 años?"
Adquiera el hábito de escribir código sin advertencias en primer lugar.
Tratar las advertencias como errores es solo un medio de autodisciplina: estaba compilando un programa para probar esa característica nueva y brillante, pero no puede hacerlo hasta que corrija las partes descuidadas. No hay información adicional -Werror proporciona. Simplemente establece prioridades muy claramente:
No agregue código nuevo hasta que solucione problemas en el código existente
Es realmente la mentalidad lo que es importante, no las herramientas. La salida de diagnóstico del compilador es una herramienta. MISRA C (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 una bandera para configurar) y la relación señal-ruido es muy alta. Así que 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 generar problemas en el futuro. La mayoría de las herramientas no se preocuparán por 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 bien antes de pasar a otras tareas, mientras aún ve sus deficiencias. Si deja ese código como está, depurarlo después de pasar dos meses agregando nuevas funciones será significativamente más difícil.
Una vez que tenga 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 iniciar o cancelarla y corregir las advertencias primero.
Siempre debe habilitar las advertencias del compilador porque el compilador a menudo puede decirle qué está mal con su código. Para hacer esto, pasa -Wall -Wextra al 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 -Werror al compilador.
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 finalmente 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 provocó la falla de segmentación, la línea que finalmente arrojó el error.
Arreglar la advertencia lleva a arreglar el problema... ¡Un clásico!
Una demostración de lo anterior... Considera 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ía rastrear cuál es la raíz de la causa... Tendrían que buscar qué sucedió con i y str dentro esa colosal cantidad de código de allí...
Hasta que, un día, se encontraron en la situación en la que descubren que idx se usa sin inicializar, por lo que tiene un valor basura, lo que resulta en la indexación de la cadena (camino) 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!
Esta es una respuesta específica a C, y por qué esto es mucho más importante para C que 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 todos los demás idiomas del planeta (salvo el lenguaje ensamblador) son advertencias en C. Las advertencias en C casi siempre son errores disfrazados. Las advertencias deben corregirse, no suprimirse.
Con GCC, hacemos esto como gcc -Wall -Werror .
Esta fue también la razón de la gran cantidad de comentarios sobre algunas advertencias de API no seguras de Microsoft. La mayoría de las personas que programan C han aprendido por las malas a tratar las advertencias como errores y aparecieron estas cosas que simplemente no eran el mismo tipo de cosas y querían soluciones no portátiles.
Las otras respuestas son excelentes y no quiero repetir lo que han dicho.
Otro aspecto de "por qué habilitar las advertencias" que no se ha abordado correctamente es que ayudan enormemente con el mantenimiento del código. Cuando escribes un programa de tamaño significativo, se vuelve imposible mantenerlo todo en tu cabeza al mismo tiempo. Por lo general, tiene una o tres funciones en las que está escribiendo y pensando activamente, y quizás uno o tres archivos en su pantalla a los que puede consultar, pero la mayor parte del programa existe en algún lugar en segundo plano y tiene que confiar en que sigue trabajando
Tener advertencias, y tenerlas lo más enérgicas y directas posible, ayuda a alertarlo si algo que cambia le causa problemas a algo que no puede ver.
Tomemos, por ejemplo, la advertencia de Clang -Wswitch-enum . Eso activa una advertencia si usa un interruptor en una enumeración y pierde uno de los posibles valores de enumeración. Es algo que podría pensar que sería un error improbable de cometer: 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 generó las opciones de cambio por usted, sin dejar espacio para el error humano.
Esta advertencia realmente cobra sentido 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 esos que necesita la opción adicional, es muy fácil olvidarse de actualizar un interruptor en un archivo que no ha tocado durante seis meses.
Puede pensar en las advertencias de la misma manera que pensaría en los casos de prueba automatizados: lo ayudan a asegurarse de que el código sea sensato y haga lo que necesita cuando lo escribe por primera vez, pero ayudan aún más a asegurarse de que sigue haciendo lo que necesitas mientras lo empujas. La diferencia es que los casos de prueba se ajustan muy estrechamente a los requisitos de su código y usted tiene que escribirlos, mientras que las advertencias funcionan ampliamente con estándares sensatos para casi todo el código, y los cerebritos que hacen los compiladores las proporcionan generosamente.
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, usar -Wall y -Wextra e incluso -Wshadow se ha vuelto vital. No voy a tratar todos los peligros, pero enumeraré algunos que han aparecido que ayudaron a mostrar problemas de código.
Este puede señalar fácilmente el trabajo sin terminar y las áreas que podrían no estar usando 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 problemas. -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)
Este fue un poco difícil y no apareció hasta que se usó -Wshadow . Modifiquemos el ejemplo anterior para simplemente agregar, 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 -Wshadow estaba activado, 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í
Esto no requiere indicadores adicionales 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 del tipo 'int', pero el argumento 2 tiene el 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.
Las advertencias del compilador en C++ son muy útiles por algunas razones.
Permite mostrarle dónde puede haber cometido un error que puede impactar en el resultado final de sus operaciones. Por ejemplo, si no inicializó una variable o si usa "=" en lugar de "==" (solo hay ejemplos)
También permite 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 mostrarte dónde tienes errores en tu código que pueden afectar el resultado de tu algoritmo o prevenir algún error cuando el usuario use tu programa.
Definitivamente, debe habilitar las advertencias del compilador, ya que algunos compiladores son malos para informar algunos errores de programación comunes, incluidos los siguientes:
Entonces, como estas funciones se pueden detectar e informar, generalmente no de manera predeterminada; por lo que esta característica debe solicitarse explícitamente a través de las opciones del compilador.
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.
Ignorar las advertencias significa que dejó un código descuidado que no solo podría causar problemas en el futuro a otra persona, sino que también hará que los mensajes de compilación importantes pasen desapercibidos para usted.
Cuanta más salida del compilador, menos nadie se dará cuenta o se molestará. Cuanto más limpio, mejor. También significa que sabes lo que estás haciendo. Las advertencias son muy poco profesionales, descuidadas y arriesgadas.
Solo hay un problema al tratar las advertencias como errores: cuando usa código proveniente de otras fuentes (por ejemplo, bibliotecas de Microsoft, proyectos de código abierto), no hicieron bien su trabajo y compilar su código genera toneladas de advertencias.
Siempre escribo mi código para que no genere advertencias ni errores, y lo limpio hasta que compila sin generar ningún ruido extraño. La basura con la que tengo que trabajar me horroriza, y me sorprende cuando tengo que construir un gran proyecto y ver pasar una serie de advertencias donde la compilación solo debería 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...
Las advertencias del compilador son tus amigos
Trabajo en sistemas Fortran 77 heredados. El compilador me dice cosas valiosas: el tipo de datos del argumento no coincide en una llamada de subrutina y el uso de una variable local antes de que se haya establecido un valor en la variable, si tengo una variable o un argumento de subrutina que no se usa. Estos son casi siempre errores.
Cuando mi código compila limpiamente, el 97% funciona. El otro tipo con el que trabajo compila con todas las advertencias desactivadas, pasa horas o días en el depurador y luego me pide ayuda. Solo compilo su código con las advertencias y le digo qué arreglar.
El hecho de que los compiladores de C++ acepten código de compilación que obviamente da como resultado un comportamiento indefinido es una falla 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 deberían ser errores fatales que impiden que se complete la compilación. Los valores predeterminados para mostrar errores y hacer 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 el programa se bloquee y haga cosas al azar.
Una vez trabajé para una gran empresa (Fortune 50) que fabricaba equipos de prueba electrónicos.
El producto central de mi grupo fue un programa MFC que, a lo largo de los años, llegó a generar literalmente cientos de advertencias. Los cuales fueron ignorados en casi todos los casos.
Esta es una maldita pesadilla cuando ocurren errores.
Después de ese puesto, tuve la suerte de que me contrataran como primer desarrollador en una nueva startup.
Alenté una política de "sin advertencia" para todas las compilaciones, con niveles de advertencia del compilador configurados para ser bastante ruidosos.
Nuestra práctica era usar la advertencia #pragma : empujar/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.