He estado codificando durante seis meses y todavía depuro a través de impresiones en stdout. ¿Debo aprender algo más?

A veces, cuando eres muy bueno con una herramienta, eres reacio a aprender otras que a veces podrían ser más poderosas. Me gusta la simplicidad de los mensajes estándar. Especialmente si usa contenedores que los habilitan / deshabilitan en función de una variable de tiempo de ejecución o un indicador de tiempo de compilación. Esta técnica prevalece en varias herramientas y demonios de línea de comandos de código abierto de Linux. stdout se puede redirigir a un registro o / dev / null que facilita la gestión del flujo de datos, incluso si se hace grande. El siguiente paso es usar stderr para la depuración: esto le permite distinguir entre diagnóstico / depuración y la salida real del programa que puede ir a stdout.

Sin embargo, a pesar de lo poderosos que son los volcados stdout / stderr, existen otras herramientas que a veces hacen el trabajo más rápido. Suponga que está trabajando con una estructura / objeto que tiene muchos miembros, desea volcarlos todos una o dos veces con fines de aprendizaje, pero esto no justifica escribir un volquete completo. Puede usar gdb para establecer puntos de interrupción e imprimir esos objetos.

Otro ejemplo: su programa se bloquea con un segfault. Puede usar gdb para averiguar dónde se bloqueó y en qué estaban las variables cuando sucedió. Si un bloqueo es particularmente misterioso, es posible que deba desmontar el código alrededor del valor del PC bloqueado (registro del contador del programa) y examinar los registros; nuevamente, gdb puede ayudar.

gdb también puede ser muy útil para depurar puntos muertos de subprocesos de pthread, aunque esto requiere cierto conocimiento del ensamblaje y los internos de pthread, puede ver qué hilos están tratando de adquirir un bloqueo y qué hilos lo están reteniendo.

Otro uso de gdb es el diagnóstico en tiempo de ejecución: puede adjuntarlo a su proceso y descubrir por qué está utilizando un 100% de CPU o no responde a los comandos. Incluso puede hacerlo con una interrupción muy mínima como esta:

gdb -p $(pidof your_process_name) --batch --ex "set pagination 0" --ex "thread apply all bt"

Como se mencionó anteriormente, afirmar () también es una poderosa herramienta de depuración. Me gusta usar una envoltura que arroje algo para que los “mortales” se queden porque todo lo que hace cuando falla es bloquear el programa con un coredump: quieres algo diagnóstico que no implique “hurgar en el núcleo” para tener alguna idea de la causa del accidente

A veces soy demasiado vago para usar mis propios diagnósticos o gdb, y recurro a strace. Esto es adecuado en particular cuando estoy haciendo una misteriosa llamada a la API para la cual no tengo la fuente, o soy demasiado flojo para leerla, y sé que la clave de la solución está oculta en algún lugar de la comunicación entre la aplicación y El sistema operativo. Strace le dirá exactamente lo que está sucediendo en el nivel del sistema operativo detallando cada intento de abrir un archivo, hacer una conexión de red, asignar memoria del sistema, etc. A lo largo de los años he resuelto muchos “imposibles” cómo diablos sabias? tipo de problemas con strace.

Los métodos anteriores son aplicables no solo a la depuración de C / C ++ porque al final del día la mayoría (si no todos) los programas escritos en un lenguaje de nivel superior ejecutarán algún código escrito en C. Por ejemplo, me pareció conveniente usar strace al depurar una aplicación PHP / MySQL para averiguar qué consultas estaba enviando a MySQL y qué estaba recuperando. Sí, podría haber agregado el registro a la clase de base de datos, pero era demasiado vago y podía leer el protocolo MySQL sin formato de manera correcta.

Aprende a escribir aserciones en tu código.

¡El efecto es como si tuviera un depurador automático siempre ejecutándose en su código!

Las afirmaciones son declaraciones sobre condiciones que espera que se cumplan en su código. C y C ++ incluso tienen macros especiales (“afirmar”) ampliamente utilizados para este propósito. Imagina que tienes una función:

flotador foo (x: flotador)
{return 1./x; }

Esperas que el argumento sea distinto de cero y positivo.
Agregue lo siguiente a su código:

flotador foo (x: flotador)
{afirmar (x> 0);
volver 1./x; }

Esto verificará que el argumento sea razonable.

Si agrega esto en las entradas a la mayoría de sus funciones, en las salidas (verifique que el resultado de la función tenga sentido), y en los puntos en el medio de los bucles, la computadora (“afirmar”) verificará que no ocurran cosas estúpidas en tu codigo. Todo el tiempo, mientras se ejecuta su programa. Y sucederá en cada carrera. Cuando “termina” el programa, la fuente recuerda todas estas pruebas; eventualmente cuando llegue a modificarlo más tarde, estas pruebas aún estarán allí.

Mi regla: si estoy mirando un punto en el código y espero que las variables en ese punto tengan alguna propiedad comprobable, escriba una afirmación. Te encontrarás escribiendo aproximadamente un 30% más de código (pero es un código fácil de escribir), y muchos de los errores en el programa se capturarán muy cerca del lugar donde ocurren.

Si afirmar es demasiado costoso para el código de producción, defina su propia macro:

#definir prueba 0
#definir confianza (una_condición_verdadera) \
if (probando &&! a_true_condition) \
trust_failure ();

Ahora escriba “confianza” en lugar de “afirmar”. Con testing == 0, esta macro no hace nada. Con testing == 1, esta macro verifica la condición y llama a trust_failure si es falsa:

flotador foo (x: flotador)
{confianza (x> 0);
volver 1./x; }

Esto tiene la propiedad realmente agradable de que puede hacer comprobaciones costosas, como verificar que una estructura de datos de entrada o la estructura resultante tenga una propiedad compleja. Por ejemplo, puedo insistir:

flotador foo (x: flotador)
{trust (x> 0 && is_prime (x))
volver 1./x
}

Solo paga el costo del cheque costoso cuando “debug == 1”. Y cuando está depurando, presumiblemente no le importan los costos de tiempo de ejecución.

(Mi empresa construye millones de sistemas de línea como este. Es sorprendente cuántos errores estúpidos detecta esto durante el desarrollo y qué tan pronto se detectan. Y no hay penalización por el código compilado en producción).

¿No codifica en C? No te quejes, tu idioma no tiene soporte para afirmaciones. Todavía puede codificar afirmaciones. Simplemente escriba una declaración if . Puedes usar el de la macro de arriba. Sí, es un poco más para codificar. Vale la pena generosamente. También puede crear una subrutina de “confianza” que acepte una condición booleana.

¡No hay excusas!

No estoy seguro de en qué lenguaje está programando, pero si está hablando de “stdout”, probablemente esté usando C o C ++, o algún otro lenguaje donde “stdout” tenga sentido.

Todos deberían tener depuradores de nivel fuente, y los depuradores de nivel fuente no son difíciles de usar. Todos tienen los conceptos de “puntos de interrupción” e imprimen los valores de las variables en estos puntos de interrupción.

Hay poca teoría de fantasía involucrada: solo use su depurador, aprenda sobre media docena de comandos u operaciones GUI en los depuradores IDE, y estará listo para comenzar.

En C / C ++ en Linux, mi depurador favorito es gdb, y también es extremadamente útil aprender a usar un rastreador de memoria y un detector de corrupción como valgrind.

Una actualización: a medida que las cosas se vuelven más complicadas, especialmente con estructuras de datos icky definidas por el contexto, como filas y páginas de bases de datos, comienza a usar una biblioteca de depuración que tiene un montón de declaraciones de impresión.

La función “call” de gdb es extremadamente útil con una biblioteca de depuración, ya que puede escribir funciones de recorrido de estructura de datos que vuelcan valores para que pueda ver el estado exacto de una estructura de datos compleja en un punto de interrupción y no tener que buscarla con mucho tedio (que a veces es imposible).

Hay muchas herramientas que pueden facilitar la depuración, avanzando por el código de una línea a la vez, pudiendo ver el ensamblaje en ejecución, etc., pero la depuración de estilo printf es realmente superior a la mayoría de los otros métodos. El programa se ejecuta casi exactamente como lo hace normalmente. No conozco otra forma de probar código multiproceso. Imprimir valores sospechosos puede ser la única forma de verificar una condición de carrera. El refinamiento de la depuración de estilo printf puede conducir a un código con un mejor registro de errores, ya que coloca las declaraciones de impresión en buenos lugares (manteniéndolos fuera de ubicaciones de ruta críticas y repetitivas, perdiéndolos en condiciones de error o atípicas).

Lo que estás haciendo se conoce genéricamente como “instrumentar tu código”. El problema al hacerlo es que cambia la forma en que se ejecuta el programa, lo que puede hacer que todo se vea bien cuando tiene el material de salida de depuración, pero no funciona cuando lo saca o lo deshabilita. Aquí es donde su jefe o mentor dice: “¡Encienda el depurador!”

Si no está dispuesto o no puede hacerlo, su trabajo puede estar en peligro. Llevaba 17 años trabajando antes de usar un depurador. Finalmente, en 1994, mi jefe amenazó con despedirme si no aprendía a usar uno dentro de un mes. En ese momento no había libros sobre el uso de estas herramientas, así que hice cosas como imprimir el texto de las pantallas de ayuda y conseguir que otros programadores me ayudaran. Me volví lo suficientemente capaz como para no perder mi trabajo, sino solo porque estaba muy motivado. Sin embargo, una vez que me puse al día, vi cuán tonto había sido luchar para aprender a depurar usando un depurador.

¡Es genial! Una vez que aprenda a colocar puntos de interrupción e inspeccionar variables, se sorprenderá de lo rápido que puede encontrar errores en tiempo de ejecución. Ser bueno en la depuración también es un verdadero refuerzo de carrera. Muchas tiendas no lo contratarán a menos que pueda usar depuradores. Es la diferencia entre personas de nivel de entrada y profesionales reales.

Hay algunos errores que solo se pueden encontrar con un depurador, y a veces solo con un depurador remoto. Estaba trabajando en “dibujar código” en Microsoft y tenía problemas con los controladores de mensajes para la ventana personalizada que estaba escribiendo. Cuando traté de usar un depurador en él, las actualizaciones y los rediseños de las pantallas de depuración interfirieron con lo que estaba tratando de ver en el código que estaba depurando. La única forma de “congelar” la acción de dibujar y ver lo que estaba sucediendo, paso a paso, era ejecutar el depurador en otra computadora con una consola remota. Al principio parecía extraño y arcano, pero verlo funcionar hizo que la corrección del error fuera trivial. El problema tenía que ver con el orden de los controladores de mensajes y qué controladores se llamaban realmente. Al poner puntos de interrupción en los controladores, pude pasar mi código mientras miraba lo que sucedía en la pantalla. Pan comido.

Expandiría un poco tu arsenal:

  • como ya se mencionó, desarrolle una habilidad para afirmaciones informativas bien ubicadas;
  • envíe sus rastreos codificados a stderr en lugar de stdout, para que pueda obtener cierta separación entre la salida de su propio código y los rastreos.
  • vea si puede obtener un buen entorno de desarrollo integrado (IDE), incluso puede encontrar versiones gratuitas que hacen lo que necesita, y aprenda cómo aprovechar sus puntos de interrupción y vigilancia de datos. Estos le permiten obtener mucha más información sobre lo que están haciendo sus carreras que simplemente enterrarse bajo una secuencia de rastros, y no implican salidas espurias que algún día (con suerte pronto) tendrán que eliminarse.

    Un depurador integrado en el entorno de desarrollo del lenguaje puede aprovechar las declaraciones de datos estructurados para hacer visualizaciones de datos más coherentes, como toda la clase o registros (estructuras) o matrices.

    Además, un depurador integrado razonable admitirá puntos de interrupción condicionales, por lo que puede desactivar temporalmente algunos de ellos (tener que reanudar constantemente desde puntos de interrupción que no le dicen nada en la ejecución actual puede volverlo loco) o configurarlos para que se rompan solo después de un número dado de pases sobre ellos.

  • gdb, como se mencionó en otra parte, es de hecho una poderosa herramienta de depuración: a veces la uso para tratar de evitar bloqueos en el programa ocasional de Mac OS X. Un montón de capacidades. El inconveniente es que, como todos están basados ​​en texto, debes aprender los comandos y qué hacen exactamente, y seguir ampliando tu repertorio.
  • pero no pierdas tus habilidades para mantener el rastro ocasional nuevamente. Habrá momentos en los que solo necesite un poco de rastreo para resolver algo, cuando las herramientas más potentes requerirán tiempo y esfuerzo para configurarlas, que pueden no ser necesarias.

Felicidades, estás usando las mismas técnicas que aprendí en los años 70. Si se toma en serio la creación de software con una larga vida útil, aprenda el desarrollo basado en pruebas. Con TDD, evita defectos. lo que está haciendo es depurar la programación posterior. Eche un vistazo a The Physics of Test-Driven Development.

Dependiendo de su plataforma de desarrollo, puede tener a su disposición herramientas de depuración muy potentes y fáciles de usar. Estas herramientas generalmente pueden detectar muchas cosas, como pérdidas de memoria y crear un perfil de su aplicación para encontrar cuellos de botella. Los puntos de interrupción le brindan la oportunidad de detener la ejecución donde elija y examine las variables. Dicho todo esto, a veces solo quieres un registro de consola rápido y sucio (stdout / stderr, syslog, etc.). ¡Solo recuerde eliminar o deshabilitar esa salida una vez que haya resuelto su problema!

Con el tiempo, debe aprender a usar todas las herramientas a su disposición, que incluyen declaraciones printf / trace / log, depuradores / IDEs, analizadores de memoria como valgrind / memcheck, etc.

De manera similar, con el tiempo aprenderá cuál es más eficaz para usted en qué circunstancia.

Si está siendo particularmente torturado, obtendrá rastros de pila sin etiquetar y volcados de memoria del tipo enviado por las herramientas de “informar información de bloqueo”. Esos son los peores para tener que trabajar.

Uso un depurador ampliamente (C #), pero a menudo con declaraciones de impresión en la consola (similar a stdout). A menudo, pongo la instrucción Write después de una prueba solo como un marcador de posición donde puedo detener el depurador.

Si surge un problema cuando una acción desencadena múltiples eventos, la acción del depurador puede alterar la ejecución del programa, de modo que avanzar por el programa en el depurador evita u oculta el error.

También me resulta más difícil usar un depurador cuando el problema está en una estructura try / catch. Insertar declaraciones que dejan un rastro de migas de pan puede ser muy útil para encontrar en qué parte del bloque se encuentra el error.

Muchos ya han señalado varios otros métodos para la depuración.
Sin embargo, según su pregunta, busca la motivación para salir de estas técnicas tradicionales (depuración mediante el método de impresión)

Bueno, estoy seguro de que habrías escuchado

Heisenbug

“heisenbug es un error de software que parece desaparecer o alterar su comportamiento cuando uno intenta estudiarlo”

bueno, encontré muchos errores en los que ninguna de las técnicas de depuración funcionaba. Necesita una combinación de habilidades de depuración (análisis de su huella de memoria, pila de llamadas, errores transitorios y método de impresión fuera de pista). Cuanto más bueno sea con estas habilidades, mejor resolverá los problemas del código.

¡Espero que te motive para aprender nuevas técnicas!

PD: perdona mi error de escritura!

Depende del tamaño del proyecto. Estoy codificando desde hace 5 años y todavía depuro imprimiendo valores en diferentes puntos. Pero cuando la estructura subyacente es demasiado compleja y stdout está inundado por una gran cantidad de mensajes, es posible que desee realizar una de las siguientes acciones:

Inicio de sesión, como algunos ya sugirieron. Esencialmente, ya no escribes en stdout sino en un archivo de registro. Escriba un buen registrador o importe uno desde algún lugar y estará listo, reutilizable en cualquier proyecto.

La mayoría de los registradores también tienen una configuración “detallada”, que puede poner en alguna forma de modo “solo mensajes de error de impresión”. Esto puede ayudar mucho al buscar errores.

Escribir pruebas para estructuras independientes. No sé si c ++ tiene un buen soporte de pruebas unitarias, pero en algún momento es posible que deba aprender cómo usarlos. Es muy, muy importante garantizar cierto comportamiento a partir de esta estructura o ese algoritmo. Tener la opción de probar con un clic si todo sigue haciendo lo que espera que haga no tiene precio.

Utiliza un depurador. Nunca me entusiasmé con ellos, siempre sentí que podía lograr lo mismo con varias impresiones, y en algunos casos realmente complicados en los que querrías un buen depurador, como una extraña función recursiva, son prácticamente inútiles.

Además de lo que Arun Venugopal mencionó, también debe aprender el registro (Ejemplo: Log4J para Java), que puede pasar a su código de producción, para depurar problemas en tiempo real.

He estado codificando durante unos 25 años y todavía uso printf para el 99% de mi depuración, muy, muy, muy raramente siento la necesidad de usar GDB o cualquier otra cosa.

Si printf funciona para usted, continúe haciéndolo, si siente que necesita algo más poderoso, continúe y aprenda.

Vale la pena aprender a usar un depurador. Es realmente agradable poder recorrer el código e inspeccionar variables sobre la marcha, en lugar de imprimirlas. Dicho esto, todavía uso declaraciones impresas todo el tiempo. Es un método válido de depuración, pero para errores sutiles, usar un depurador puede ser invaluable.

Si está usando C, entonces seguiría los consejos de Greg y usaría gdb. Para el registro, si se trata de un sistema Linux / Unix, defiendo el uso de syslog.

Si está utilizando Java, entonces su amigable depurador de vecindario tendrá capacidades de depuración tales como relojes integrados. Úselo.

Para iniciar sesión, es mejor usar un marco de registro. El más simple y construido en uno es java.util.Logging. También hay muchos más avanzados por ahí.

http://docs.oracle.com/javase/7/

Deje de usar la impresión para stdout lo antes posible.

Las respuestas que he visto son muy buenos consejos:
– Aprende a usar un depurador
– Usar afirmaciones
– Examen de la unidad

Con respecto a su uso de declaraciones printf / cout. Esos también son geniales, cuando en cambio son parte de una estrategia de registro. Una buena estrategia de registro le permite depurar su programa, una vez que sale de la línea de producción y se implementa. Sin embargo, algunas de esas declaraciones se reemplazarán mejor por afirmaciones, según corresponda.

Definitivamente, le aconsejaría que aprenda a usar un depurador, incluso en su forma básica, será tremendamente útil.

El aprendizaje es esencial, el conocimiento es el poder supremo. Puede quedarse con la impresión durante bastante tiempo si lo desea, no es un gran problema, pero como otros tendré que recomendar, un IDE es un buen depurador que le permitirá ver variables y probar el desarrollo impulsado.

Esas tres habilidades, especialmente el desarrollo basado en pruebas, son muy útiles y las personas apreciarán que tenga esas habilidades.

Pero no se sienta abrumado, tómese su tiempo y no deje que la gente lo asuste porque lo hace mal.

Somos humanos, hacemos todo mal 😀

printf funciona bien para pequeños segmentos de código en los que (probablemente) esté trabajando.

Los depuradores son herramientas poderosas, por lo que en algún momento definitivamente debería aprender a usar uno (una vez que sepa cómo usar uno, verá que la mayoría de los demás son muy similares), pero en esta etapa de su codificación puede estar abrumado con la cantidad de nuevas herramientas que tiene que usar, por lo que agregar otra puede no ser lo ideal.

No se preocupe por aprender otra herramienta hasta que tenga más experiencia y se sienta cómodo con las herramientas que está utilizando actualmente, todo lo que dice que un depurador lo sacará de algunos agujeros realmente profundos 🙂

Bueno, todo esto depende de para qué estés usando C. Encuentro introductorio C intuitivo. Por lo tanto, no es necesario usar gdb ni ningún otro depurador. Sin embargo, después de tomar mi primera clase de programación de sistemas, desarrollé la necesidad de un depurador.

Hay una razón principal para usar un depurador sobre stdout y es la memoria . Si accede a la memoria directamente, o hace suposiciones sobre dónde / cómo se almacenan las variables, o incluso algo similar, como la declaración de una variable global frente a local, puede beneficiarse de la depuración en un depurador.

Ejemplo de la vida real: una vez tuve un programa que funcionó cada vez que agregué un printf en medio de otras dos declaraciones. Pero cuando lo saqué, no funcionó. La razón es que la pila era diferente cuando la declaración printf estaba allí y cuando no lo estaba. Obviamente, estoy dejando de lado algunos detalles aquí, pero por favor, comprenda que hay una razón por la que el depurador está allí.

Sin embargo, para la mayoría de los casos fuera de estos, nunca lo necesitará.

Salud

More Interesting

Tengo úlceras en mis párpados con frecuencia. ¿Qué podría ser la causa?

He completado mi ingeniería de la India y ahora me he mudado a California. Me gustaría seguir una carrera docente. ¿Es posible con mi calificación? ¿Los indios trabajan en escuelas públicas de California? Si es así, ¿cómo puedo hacerlo?

Mi estado de ITR ha estado “No determinado” durante el último 1 año. ¿Cuál es la mejor próxima acción que puedo tomar para obtener mi reembolso lo antes posible?

Tengo 350 de 1200 en un sistema de entrada rápida para Canadá. ¿Hay algún trabajo como en un centro de atención telefónica o back office en Canadá que me ayude a obtener 900 puntos?

Quiero tener más experiencias en la vida donde explore fuera de mi zona de confort. ¿Cuál es la mejor manera de comenzar?

Quiero comprar un Pathfinder ’13 con 58K millas, de Ohio, vivo en GA. Tiene algo de óxido considerable debajo del carro. ¿Debería Preocuparme?

Hoy le envié a mi ex un mensaje de feliz cumpleaños y él lo leyó pero no respondió. ¿Es esta una señal de que no quiere tener nada que ver conmigo?

Toco la batería, me encantan las matemáticas, el espacio y los aviones voladores. Mucha gente que conozco tiene exactamente el mismo interés. ¿Hay alguna correlación entre estos?

Soy indio y solo sé hindi e inglés. ¿Cómo puedo aprender urdu, español, marathi, etc.?

Quiero trabajar en Ferrari. Soy ingeniero mecanico. ¿Cuáles son las publicaciones que están disponibles? ¿Cómo se lleva a cabo el proceso de entrevista?