El depurador no puede seguir ejecutando: causas, diagnóstico y soluciones

Cuando aparece el mensaje «el depurador no puede seguir ejecutando», normalmente existe un problema en el estado de la ejecución, en la configuración del proyecto, en la información de depuración o en el propio proceso que se intenta inspeccionar. La depuración permite colocar puntos de parada, inspeccionar variables y ejecutar un programa paso a paso, con el fin de buscar errores.

Antes de iniciar el depurador, el programa debe poder compilarse y enlazarse correctamente, generar un ejecutable y contener la información necesaria para relacionar las instrucciones del código fuente con el código máquina y las variables en memoria. Si no se cumplen estas condiciones, el depurador no podrá trabajar correctamente o solo mostrará información limitada.

Qué significa depurar un programa

La depuración de programas es el proceso por el cual se identifican y corrigen errores de programación. Generalmente, en el argot de programación se utiliza la palabra debugging, que significa localización y eliminación de bichos (bugs) o errores de programa.

A través de este proceso se descubren los errores y se identifica qué zonas del programa los producen. El debugging (conocido también como depuración de errores) es el proceso de detección, análisis y corrección de errores presentes en el código fuente de un programa.

Estos errores, también llamados bugs, pueden causar comportamientos inesperados, fallas o resultados incorrectos. Pueden manifestarse de diferentes maneras: mensajes de error, fallos intermitentes o errores lógicos invisibles sin un análisis profundo.

El debugging tiene como objetivo localizar y corregir estos problemas para asegurar el correcto funcionamiento de la aplicación. La depuración de programas es una tarea fundamental en el desarrollo de software.

Por qué el depurador puede dejar de ejecutar

Los programas no pueden ser depurados siempre, antes deben cumplir determinadas condiciones. La primera es que se pueda obtener un ejecutable. Si no llegamos a eso los errores serán de compilación o de enlazado, y un depurador no tiene sentido hasta que se solucionen todos esos problemas.

La segunda condición es que el fichero ejecutable contenga la información para la depuración. Un ejecutable que no contenga esa información se puede depurar, pero sólo en ensamblador, y no con el depurador que incluye Dev-C++.

La información de depuración consiste en el propio fichero fuente, y los lazos que unen cada una de las instrucciones del programa y variables, con las resultantes de compilar el programa, de modo que el depurador pueda saber a qué instrucciones de código máquina corresponden cada instrucción de C/C++.

Y también a qué direcciones de memoria corresponde cada variable, asi como su tipo. Para que el compilador añada esa información al programa ejecutable hay que indicar al enlazador que lo haga.

Compilación

Una vez que hemos terminado de afinar un programa, solemos pasar generalmente cierto tiempo eliminando errores de compilación. El compilador de Java mostrará una serie de chequeos en el código, sacando a la luz errores que pueden no apreciarse a simple vista.

Una vez que el programa es liberado de los errores de compilación, obtendremos de él algunos resultados visibles pero quizá no haga aún lo que queremos. Si el código no compila, el depurador no puede iniciar una ejecución normal del programa.

Enlazado

Todos los programas hacen uso de librerías de métodos y otros utilizan métodos generados por los propios programadores. Un método es enlazado (linked) sólo cuando éste es llamado, durante el proceso de ejecución.

Pero cuando el programa es compilado, se realizan comprobaciones para saber si los métodos llamados existen y sus parámetros son correctos en número y tipo. Así que los errores de enlazado son detectados durante la etapa de compilación.

Ejecución

Cuando el programa entra en ejecución, es muy frecuente que éste no funcione como se esperaba. De hecho, es normal que el programa falle.

Algunos errores serán detectados automáticamente y el programador será informado, como acceder a una parte de un array que no existe (error de índices) por ejemplo. Otros son más sutiles y dan lugar simplemente a comportamientos no esperados, debido a la existencia de errores ocultos (bugs) en el programa.

El problema de la depuración es que los síntomas de un posible error son generalmente poco claros, hay que recurrir a una labor de investigación para encontrar la causa. La depuración de programas es algo así como ser doctor: existe un síntoma, hemos de encontrar la causa y entonces determinar el problema.

Condiciones necesarias para iniciar la depuración

La primera condición consiste en disponer de un ejecutable válido. Si el proceso de compilación o enlazado falla, el depurador no tiene un proceso que pueda iniciar, detener y examinar.

La segunda condición consiste en generar el ejecutable con información de depuración. Dev-C++ es lo bastante "listo" como para hacer esto de forma automática, pero no está de más que sepamos cómo hacerlo nosotros.

Sobre todo porque dicha información aumenta considerablemente el tamaño del ejecutable, y una vez depurado, deberíamos eliminarla para crear una versión final. Si activamos la opción "Generar Información de Debug", dicha información se añadirá la próxima vez que compilemos y enlacemos el programa con éxito.

Si la desactivamos, se eliminará, del mismo modo, después de compilar y enlazar el programa. Para hacer que el enlazador incluya o no la información del depurador debemos acceder a las "Opciones del Compilador", que se encuentran en el menú de "Herramientas", y, como se ve en el siguiente gráfico, en la pestaña "Configuración" del cuadro de diálogo de "Opciones del Compilador", en las opciones del "linker".

Breakpoints y puntos de parada

Los puntos de ruptura o breakpoints son una característica útil cuando conoce la línea de código o la sección de código que desea examinar con detalle en tiempo de ejecución. Un Breakpoint es un lugar en el programa en el que la ejecución se detiene.

Estos puntos se insertan en una determinada línea del código, entonces el programa se pone en funcionamiento y cuando el flujo de ejecución llega hasta él, la ejecución queda congelada y un puntero indica el lugar en el que la ejecución se ha detenido.

El depurador muestra los valores de las variables tal y como están en ese momento de la ejecución. Cualquier discrepancia entre el valor actual y el valor que deberían tener supone una importante información para el proceso de depuración.

Los puntos de parada indican al depurador que detenga la ejecución del programa y devuelvan el control al usuario, es decir, a nosotros. Una vez detenido el programa podremos inspeccionar variables, modificarlas, continuar la ejecución, o seguir ejecutando el programa sentencia a sentencia.

punto de interrupción en código fuente

Hay dos formas de activar un punto de parada, breakpoint. La más sencilla es pulsar con el ratón en la zona del margen junto a la línea en la que queremos situar el pulto de parada.

Otra forma es situar el cursor en la línea en que queremos situar el punto de parada y usar el menú "Depurar->Añadir/Quitar punto de Ruptura". En cualquiera de los casos, se visualizará la línea con fondo rojo, y un icono rojo con una 'V' verde en su interior en la zona del margen.

Para eliminar un punto de parada se procede del mismo modo. Los puntos de interrupción pueden ser simples, condicionales o asociados a funciones, según las posibilidades del entorno utilizado.

Ejecución paso a paso

El depurador también nos permite ejecutar un programa paso a paso, es decir, línea por línea. A través de esta herramienta podremos seguir el progreso de ejecución de nuestra aplicación y supervisar su funcionamiento.

Cuando la ejecución no es la esperada quizá estemos cerca de localizar un error o bug. En ocasiones, si utilizamos métodos procedentes de la biblioteca estándar no necesitaremos hacer un recorrido paso a paso por el interior de éstos métodos, ya que es seguro que no contendrán errores internos y podremos ahorrar tiempo no entrando en su interior paso a paso.

El debugger ofrece la posibilidad de entrar o no en dicho métodos. La diferencia entre "siguiente paso" y "paso a paso" es sutil pero importante.

La primera opción ejecuta cada sentencia como un único paso, por ejemplo, si tenemos una sentencia como: for(int i=0; i < 12; i++) x[i] = i; "Siguiente paso" la ejecutará de una sola vez, mientras que "paso a paso" ejecutará cada una de las iteraciones.

Si la sentencia contiene una llamada a una función, "siguiente paso" la ejecutará como una sentencia única, y "paso a paso" transferirá la ejecución al interior de la función y ejecutará sus sentencias paso a paso.

Comandos de navegación del depurador

Para iniciar la aplicación con el depurador asociado, presione F11 (Depurar > paso a paso por instrucciones). F11 es el comando Step Into y avanza la ejecución de la aplicación una instrucción a la vez.

Cuando se inicia la aplicación con F11, el depurador se interrumpe en la primera instrucción que se ejecuta. La flecha amarilla representa la instrucción en la que el depurador se ha detenido, lo cual también suspende la ejecución de la aplicación en el mismo punto (esta instrucción todavía no se ha ejecutado).

F11 es una buena manera de examinar el flujo de ejecución con más detalle. Cuando se encuentre en una línea de código que sea una llamada de función o método, puede presionar F10 (Depurar > Depurar paso a paso por procedimientos) en lugar de F11.

F10 hace avanzar el depurador sin depurar las funciones ni los métodos del código de la aplicación paso a paso por instrucciones (el código se sigue ejecutando). Al presionar F10, puede omitir el código que no le interesa.

A veces, es posible que quiera continuar la sesión de depuración pero avanzar el depurador hasta el final de la función actual. Presione Mayús + F11 (o bien Depurar > Salir de la depuración).

Este comando reanuda la ejecución de la aplicación (y avanza el depurador) hasta que la función actual retorne. También es posible ejecutar temporalmente hasta una línea concreta sin conservar un punto de parada permanente.

Otra variante de punto de parada consiste en situar el cursor en la línea hasta la que queremos que se ejecute el programa y pulsar "Ir al cursor". Esto trabaja igual que si hubiéramos situado un punto de parada en esa línea, y lo borráramos una vez alcanzado.

Pero cuidado, el resto de los puntos de parada siguen activos, si se alcanza uno de ellos antes que la posición del cursor, el programa parará en ese punto.

Al editar código (en lugar de pausar en el depurador), haga clic con el botón derecho en una línea de código de la aplicación y elija Ejecutar al cursor (o presione Ctrl + F10).

Este comando inicia la depuración y establece un punto de interrupción temporal en la línea de código actual. Si establece puntos de parada, el depurador se detiene en el primer punto de parada que encuentra.

Inspección de variables y expresiones

María, que estaba codificando un nuevo método, se detiene un momento y pregunta: -Entonces, ¿cuando el programa llega al Breakpoint podré saber qué valor tiene una variable determinada?

-Efectivamente María, y podrás saber el valor de aquellas que tú decidas. De este modo a través de los puntos de ruptura y de las ejecuciones paso a paso podrás descubrir dónde puede haber errores en tus programas.

Mientras la ejecución está detenida podemos consultar el valor de las variables accesibles desde el punto de ejecución actual. Añadir variables a la lista es fácil, basta con pulsar en "Añadir watch" y escribir el nombre de la variable a visualizar.

Igual de sencillo es eliminarlas: seleccionamos la variable a borrar y pulsamos sobre el icono "Quitar watch". Existe otra herramienta, aunque parece que en la versión actual de Dev-C++ aún no está muy conseguida.

Consiste en modificar el valor de alguna de las variables observadas. Pulsando sobre la variable en la lista, con el botón derecho aparece un menú. La segunda opción tiene un icono con un martillo, "Modificar valor".

Información sobre datos

Cuando el depurador está pausado, pase el ratón sobre un objeto y verá su valor o su valor de propiedad predeterminado. Si la variable tiene propiedades, puede expandir el objeto para ver todas sus propiedades.

A menudo, al depurar, necesita poder comprobar rápidamente los valores de propiedad de los objetos, y la información sobre datos es una buena forma de hacerlo. En la ventana Autos, ve las variables junto con su valor actual y su tipo.

En la ventana de Automático se muestran todas las variables usadas en la línea actual o en la línea anterior. En la ventana Variables locales se muestran las variables del ámbito actual.

Ventanas de inspección

Puede usar una ventana Inspección para especificar una variable o una expresión que quiera supervisar. Mientras depura, haga clic con el botón derecho en un objeto y elija Agregar inspección.

En este ejemplo, se ha establecido una inspección para el objeto y puede ver cómo cambia su valor conforme avanza en el depurador. A diferencia de las otras ventanas de variables, las ventanas Watch siempre muestran las variables que estás observando (están atenuadas cuando están fuera del ámbito).

Examinar la pila de llamadas

En la ventana Pila de llamadas se muestra el orden en el que se llama a los métodos y las funciones. La línea superior muestra la función actual.

La segunda línea muestra la función o la propiedad desde la que se llamó, etc. La pila de llamadas es una buena manera de examinar y comprender el flujo de ejecución de una aplicación.

Puede hacer doble clic en una línea de código para ver ese código fuente, lo cual también cambia el ámbito actual inspeccionado por el depurador. Eso no hace avanzar el depurador.

También puede usar los menús contextuales de la ventana Pila de llamadas para hacer otras cosas. Por ejemplo, puede insertar puntos de interrupción en funciones concretas, reiniciar la aplicación mediante Ejecutar hasta el cursor y examinar el código fuente.

Excepciones y errores durante la ejecución

Cuando la aplicación produce una excepción, el depurador le lleva a la línea de código que ha producido esa excepción. El asistente de excepciones muestra una System.NullReferenceException excepción y un mensaje de error que indica que la referencia de objeto no está establecida en una instancia del objeto.

Además, nos indica que el valor de cadena era NULL cuando intentó llamar al método Trim. El asistente de excepciones es una característica excelente que puede ayudarle a depurar errores.

También se pueden hacer cosas como ver detalles de errores y agregar una inspección desde el Asistente de excepciones. O bien, si fuera necesario, se pueden cambiar las condiciones para producir la excepción concreta.

Expanda el nodo Configuración de Excepciones para ver más opciones sobre cómo gestionar este tipo de excepción, ¡pero no es necesario cambiar nada durante este recorrido!

Ejecutar, reiniciar y detener la depuración

Presione F5 (Depurar > Iniciar depuración), que es el método más común. Después de establecer puntos de interrupción, está listo para iniciar la depuración.

Los puntos de interrupción son la característica más básica y esencial para una depuración confiable. Un punto de interrupción indica dónde Visual Studio debe suspender el código en ejecución para que pueda echar un vistazo a los valores de las variables, o el comportamiento de la memoria, o si se ejecuta o no una rama de código.

Presione F5 (Depurar > Iniciar depuración) o el botón Iniciar depuración en la barra de herramientas de depuración y el depurador se ejecuta en el primer punto de interrupción que encuentra.

En cualquier caso, el programa se ejecutará normalmente hasta alcanzar un punto de parada. En ese momento el control vuelve al entorno de Dev-C++ y se muestra la línea de ejecución actual con fondo azul y con un icono en forma de flecha en el margen.

Seleccione el botón Reiniciar en la barra de herramientas depurar (o presione Ctrl + Mayús + F5). El botón Reiniciar permite ahorrar tiempo, ya que hace que no sea necesario detener la aplicación y reiniciar el depurador.

El depurador se detiene en el primer punto de interrupción que se alcanza al ejecutar el código. Si quiere detener el depurador y volver al editor de código, puede presionar el botón rojo de parada en lugar de Reiniciar.

Si el programa ha entrado en una situación en la que hemos perdido el control, o sencillamente, no nos interesa continuar depurando, podemos detener la ejecución mediante la opción "Parar ejecución", ya sea en el menú de "Depurar" o en la zona de depuración inferior.

Parámetros de ejecución

Si nuestro programa necesita recibir parámetros desde la línea de programa, podemos suministrarlos mediante la opción del menú "Depurar->Parámetros. ". Esto nos permite simular una orden desde la consola con la lista de parámetros que prefiramos.

Los parámetros de entrada son importantes cuando el error solo aparece bajo determinadas condiciones. La primera etapa consiste en comprender la anomalía.

Se trata de reproducir el bug para observar sus efectos y determinar las condiciones exactas en las que ocurre. A veces, el problema puede manifestarse solo en entornos específicos o bajo ciertas cargas.

Cuando el programa se ejecuta demasiado lentamente bajo el depurador

Saben que en ZinjaI (y en muchísimos otros IDEs) tenemos dos formas de ejecutar un proyecto: la "normal" y la "debug". La "normal" (Ejecución->Ejecutar o F9) guarda, compila y ejecuta el resultado como si hubiésemos hecho doble click en el exe desde el explorador de archivos.

La ejecución "debug" (Depuración->Iniciar o F5), en cambio, ejecuta a través de gdb. Es decir, ejecuta gdb (el verdadero depurador que hay detrás de ZinjaI), y le pide a este que cargue y ejecute el exe.

Para tener control sobre esta ejecución, gdb puede hacer internamente cosas raras, normalmente sin que lo notemos. Me dí cuenta hace poco que en Windows alguna de estas cosas raras puede hacer que el programa corra mucho más lento que en la ejecución normal.

Y cuando un programa, en su ejecución normal revienta luego de unos pocos minutos de proceso, este "enlentecimiento" se torna un problema grave, porque para intentar depurarlo debemos esperar una eternidad hasta llegar al problema, cada vez que lo probamos.

ModoTiempo de ejecución
Ejecución normal8 segundos
Ejecución con depurador140
Relación indicada17.5 veces

Para poner unos números de ejemplo, un caso que tengo a mano tarda 8 segundos en finalizar en la ejecución normal, y 140 (17.5 veces) en el depurador.

Algunos depuradores instrumentan de forma transparente funciones estándar, y esto es lo que los hace lentos. Por ejemplo, el de Visual Studio agrega cosas al reservar y liberar memoria dinámicamente (aunque no se si el debugger o el compilador), que luego le permiten detectar errores y hacer cierto profiling.

Pero gdb y gcc, hasta donde conozco, no hacen nada de esto. Gdb simplemente debería poner el programa a correr con normalidad, interceptando solo las señales que este recibe, que es lo que usa para detener la ejecución.

Una cosa rara puede ser un watchpoint, o un breakpoint condicional, cosas que pueden obligar al depurador a detener el proceso frecuentemente para inspeccionar la memoria. Pero en Windows, aunque no haga nada ni defina nada, igual corre más lento.

Es más, aunque lo que ejecute no tenga información de depuración, igual a veces va mucho más lento. Todavía no puedo explicar por qué, pero hoy voy a hablar de un workaround (un parche-truco) para poder depurar igual sin perder la paciencia.

Depurar un fallo sin esperar a que ocurra

En GNU/Linux hay una forma fácil de resolver esto, que consiste en activar los core-dumps. Esto hace que cuando un programa reviente (en ejecución normal, sin depurador de por medio) el sistema escupa todo lo que el programa tenía en la memoria en un archivo (llamado "core", en el directorio de ejecución), que luego puede ser cargado con gdb para analizar el estado que tenía el programa y sus variables al momento de reventar, y tratar así de descubrir qué fue lo que falló.

En ZinjaI ya se puede analizar un core (Depuración->Más->Cargar vocado de memoria), y en la próxima versión tendrán una opción en las preferencias para que ZinjaI active la generación de cores automáticamente.

En Windows, la idea que propongo es la siguiente: hacer que el proceso corra fuera del depurador (es decir, ejecución "normal") hasta el punto en que revienta, y justo ahí carguemos el depurador para ver qué pasó.

Entonces hay que lograr dos cosas: (primero) hacer que el proceso no se cierre cuando se produce el error, para (segundo) conectarle el depurador de alguna manera.

Adjuntar el depurador a un proceso activo

Esto de "conectar" el depurador a un proceso "vivo" que se lanzó por fuera, se llama "adjuntar", y está disponible en ZinjaI para GNU/Linux desde hace rato (Depuración->Más->Adjuntar. ).

La próxima versión lo tendrá disponible también para Windows. No lo tenía anteriormente porque lo había probado y no me había funcionado.

Ahora tengo una versión actualizada de gdb, y además noté una diferencia en la salida del mismo a la hora de adjuntar un proceso entre sus versiones para Windows y GNU/Linux.

No se si el "no andaba" era porque en las versiones viejas realmente gdb tenía problemas, o porque yo desde ZinjaI no había considerado las diferencias, pero en cualquier caso ahora me anda, así que será una funcionalidad usable para la próxima versión.

Detener el proceso mediante una señal

Lo que falta decir es cómo hacerlo en el momento justo. Tenemos que lograr "pausar" el proceso cuando se produce el error.

La forma de lograrlo es instalándole un manejador de señales para las señales de error. Un manejador de señales es una función que se ejecuta cuando el proceso recibe ciertas señales (tipo callback), y se hace desde el código mediante la función signal.

La señal que nos interesa es usualmente SIGSEGV (la "violación de segmento" en GNU/Linux, el "acceso ilegal" en Windows).

Y es en esa función donde ponemos un código que espere:

void my_handler(int sig_num) { cout << "Signal: " << sig_num << endl; cout << "PID: " << GetCurrentProcessId() << endl; cin.get(); }

int main() { signal( SIGSEGV, my_handler ); int *p = 0; cout << *p; // KBOOM!!! }

Este manejador informa de la señal, muestra el id del proceso con una función de la api de Windows (porque es lo que vamos a necesitar para decirle a gdb a quién adjuntarse), y espera una tecla.

Este "esperar" es el que detiene todo justo en medio de la hecatombe para darle lugar al depurador. Entonces, podemos ejecutar el programa normalmente, y al ver el mensaje adjuntar el depurador a ese proceso.

Seleccionar el hilo correcto

Pero hay un detalle importante a tener en cuenta: el backtrace que vamos a ver no va a decir nada útil, va a estar lleno de "??".

Al adjuntar el depurador en ese momento pasan dos cosas: por un lado el proceso tiene en ese punto dos hilos, y el depurador aparece en un hilo que no es el del segfault.

Si mostramos el panel de hilos (Depuración->Hilos de ejecución) y cambiamos al otro, veremos en el backtrace la llamada al manejador de la señal.

Pero seguiremos sin ver cómo se llegó hasta allí. Es decir, el resto del backtrace (arriba y abajo del manejador) seguirá siendo "??".

Otra vez no sé porqué ocurre esto (en GNU/Linux no me pasa), pero también es fácil de solucionar. Simplemente tratamos de continuar la ejecución (F5 otra vez).

Como la función manejadora no termina el programa (debería terminar invocando a abort o exit), retorna y se vuelve al punto del error, pero como el error no está corregido, vuelve a explotar, y ahora ya tenemos a gdb listo para interceptar esta segunda explosión.

Proceso de diagnóstico paso a paso

Identificar el problema: La primera etapa consiste en comprender la anomalía. Se trata de reproducir el bug para observar sus efectos y determinar las condiciones exactas en las que ocurre.

Localizar el bug en el código fuente: Una vez identificado el problema, el desarrollador analiza el código para encontrar la ubicación exacta del error. Esto puede requerir el uso de registros de eventos (logs) o de un depurador para seguir la ejecución del programa paso a paso.

Analizar la causa: El depurador debe entender por qué ocurre el bug. Esto puede implicar verificar las interacciones entre diferentes componentes, identificar errores de lógica o volver a verificar los datos de entrada y los métodos utilizados.

Modificar y probar: Después de corregir el código, es esencial probar la modificación para asegurarse de que el problema se resuelva sin crear nuevos. Puede ser necesario realizar pruebas unitarias y pruebas de regresión para garantizar la estabilidad del programa.

Documentar las correcciones: Una buena documentación ayuda a los equipos a entender las correcciones realizadas. Permite mantener un historial de modificaciones, mejorar las buenas prácticas de codificación y prevenir errores similares en el futuro.

Pruebas y depuración

La fase de pruebas de una aplicación software es una etapa fundamental que en numerosas ocasiones puede suponer un tanto por ciento importante del tiempo de desarrollo del proyecto. Esta fase es planificada por los desarrolladores/analistas de acuerdo a los requisitos establecidos en la etapa de análisis, por lo tanto, no se trata de una fase improvisada.

Dentro de las pruebas a realizar se encuentran las conocidas como pruebas de caja negra o pruebas de caja blanca. Durante la etapa de implementación, los programadores deben realizar otros tipos de prueba que verifiquen el código que escriben.

Técnica de pruebas de software en la cual la funcionalidad se verifica sin tomar en cuenta la estructura interna de código, detalles de implementación o escenarios de ejecución internos en el software.

Pruebas de sistemas software que se centran en los detalles procedimentales, por lo que su diseño está fuertemente ligado al código fuente.

Ejemplo de error lógico en PSeInt

Siguiendo los pasos de esta práctica aprenderás a depurar y validar datos con PSeint. Vamos a ejecutar la opción de depuración "paso a paso" y comprobaremos cómo el depurador nos indica por dónde va el flujo del programa en cada momento, circulando a través de sus bucles de repetición según las condiciones impuestas por el programador.

Cuando en PSeInt se pulsa la opción Ejecutar. , se abre una segunda ventana: a) La primera muestra el programa, la secuencia de órdenes, el flujo, dirección y orden de ejecución. b) Y en la segunda ventana se va ejecutando propiamente el programa, solicitando los datos de entrada y mostrando los valores y resultados buscados.

Pero si queremos conocer el funcionamiento del programa, debemos ejecutarlo paso a paso: El botón Ejecutar paso a paso. permite depurar un algoritmo en Pseint.

Al pulsar en este botón, el espacio se divide en tres zonas: a) La zona del código del programa. b) A la derecha tenemos el panel "paso a paso" donde podemos elegir varias opciones que te ofrece el depurador. c) Si marcamos la opción Prueba de escritorio, abajo se nos abrirá otra ventana donde se explica qué está haciendo el programa en cada momento, donde guarda valores, en qué variables, cuales son los valores que guarda, etc.

Una vez pulsado el botón Comenzar, aparecerá la opción Agregar en una nueva ventana donde se escribirá el nombre de la variable que queremos comprobar como cambia en cada bucle o estructura de control.

Este programa calcula el promedio de los números que suministre el usuario por teclado. No, no funciona. Esto es lo que se conoce como un bug. El programa no se detiene pero hace un cálculo erróneo.

Para ayudarte a que el código funcione, utiliza la Prueba de escritorio con el valor de la variable "i" y haz el seguimiento de sus valores. Imagina que el usuario introduce un valor negativo para la variable "n". ¿Qué pasaría?

Te toca ahora mejorar el programa: Valida la entrada de datos, poniendo límites a la misma para que no permita valores negativos de "n" y dando un mensaje de error al usuario para que introduzca un dato correcto.

Introduce también un bucle que permita que no se salga del programa hasta que la entrada sea correcta. Guarda el archivo de PSeInt que incluya todas las modificaciones que has hecho.

Tipos de depuración

Existen varios métodos de debugging según el contexto y las herramientas utilizadas. El debugging manual consiste en analizar el código sin una herramienta específica, utilizando instrucciones de registro («logs») para seguir el comportamiento del programa.

Puede insertar mensajes en el código en puntos estratégicos para observar los valores de las variables o los flujos de ejecución. Este método es particularmente útil para diagnosticar errores rápidamente, pero puede ser tedioso para sistemas complejos.

Muchos entornos de desarrollo integrados (IDE) ofrecen un modo debugging. Este modo permite ejecutar el programa paso a paso, monitorear las variables y poner puntos de ruptura («breakpoints»).

Estos puntos de interrupción permiten detener la ejecución del programa en líneas específicas para inspeccionar el estado del sistema y detectar precisamente dónde se manifiesta el bug.

El debugging remoto, utilizado para depurar aplicaciones en producción o en servidores remotos, permite conectarse a un programa ejecutado en una máquina diferente.

Los desarrolladores pueden diagnosticar los errores en directo sin interrumpir completamente el servicio, pero este método requiere una configuración específica para garantizar la seguridad y el acceso al servidor.

Algunas herramientas pueden detectar y corregir automáticamente algunos tipos de bugs, especialmente errores de sintaxis, fugas de memoria o problemas de rendimiento.

Estas herramientas, a menudo integradas en IDE o en pipelines de integración continua, ayudan a mantener un código limpio y a prevenir regresiones al detectar errores antes del despliegue.

Herramientas de depuración

¿Y cómo llevamos a cabo la depuración de nuestros programas?, pues a través del debugger o depurador del sistema de desarrollo Java que estemos utilizando. Este depurador será una herramienta que nos ayudará a eliminar posibles errores de nuestro programa.

Podremos utilizar depuradores simples, como el jdb propio de Java basado en línea de comandos. O bien, utilizar el depurador existente en nuestro IDE.

Este último tipo de depuradores muestra los siguientes elementos en pantalla: El programa en funcionamiento, el código fuente del programa y los nombres y valores actuales de las variables que se seleccionen.

HerramientaDescripción
GDB (GNU Debugger)Una herramienta potente para el debugging de programas en C, C++ y otros lenguajes de bajo nivel.
Visual Studio CodeEste editor de código ofrece un modo debugging muy completo compatible con numerosos lenguajes.
Chrome DevToolsIdeal para el debugging de aplicaciones web, integrado en el navegador Chrome (HTML, CSS, JS).
XcodeUtilizado para el desarrollo Apple, con funcionalidades avanzadas de debugging.
Py!CharmUn entorno especializado para Python, con herramientas adaptadas a proyectos complejos.

Buenas prácticas para evitar bloqueos del depurador

Los ordenadores hacen sólo aquello que nosotros les decimos que hagan: si los programas no funcionan es porque no los hemos diseñado bien o porque hemos cometido algún error, y no porque el compilador o el ordenador no funcionen correctamente.

Un modo de buscar errores de programación es convertirnos en un ordenador y ejecutar el programa que hemos escrito nosotros mismos. Esto suele ser lento y laborioso.

Otro método es partir de datos conocidos y ejecutar el programa, para llegar a resultados también conocidos, o al menos que se puedan calcular. Frecuentemente se puede deducir dónde está el error en función de los errores obtenidos.

Otras veces podemos usar los mensajes de error que nos proporciona el sistema, pero en general (al menos a mi me pasa), esos mensajes no suelen arrojar mucha luz.

Durante el periodo de aprendizaje, esta es mi opinión, no se debería abusar de los depuradores. Creo que es mejor, para asentar bien las bases, depurar los programas usando cualquiera de los métodos anteriores, o incluso, mientras se hacen programas sencillos, pocas veces debería ser necesario depurar programas, y se deberían centrar los esfuerzos en un diseño correcto.

Sin embargo, a medida que nuestros programas se van complicando, las situaciones no previstas en nuestro diseño tienen a hacerse más frecuentes. El diseño es algo que hay que entrenar y perfeccionar, y un depurador puede ayudarnos a corregir nuestros errores de diseño.

Con el tiempo veremos que cada vez los necesitamos menos, y que dedicamos más tiempo a un buen diseño y menos a poner "parches" a nuestros programas.

Sea paciente: El debugging puede ser un proceso largo y tedioso. No se apresure y tómese el tiempo para analizar cada aspecto del problema.

Utilice los logs inteligentemente: Añadir mensajes de registro en su código permite seguir la ejecución e identificar más rápidamente las etapas problemáticas.

Consulte a sus colegas: A veces, una mirada externa puede ayudar a detectar errores que no ha notado.

Domine sus herramientas: Familiarícese con las herramientas de debugging propias de su entorno de desarrollo. Le ahorrarán un tiempo valioso.

Tome descansos: Si está bloqueado, tome un momento para alejarse del problema. Volverá con una perspectiva más fresca.

Depuración Just-In-Time

El cuadro de diálogo Depurador Just-In-Time (JIT) en Visual Studio podría abrirse cuando se produzcan errores en una aplicación en ejecución. El cuadro de diálogo puede impedir que la aplicación continúe con la ejecución.

El depurador JIT le ofrece la opción de iniciar Visual Studio para depurar el error. Para seguir con esta acción, debe tener Instalado Visual Studio u otro depurador seleccionado.

El depurador proporciona información detallada sobre el error y las características que le ayudarán a resolver el problema. En este artículo se explica cómo evitar que el cuadro de diálogo Depurador JIT interrumpa la ejecución de la aplicación.

Hay diferentes opciones para responder al cuadro de diálogo Depurador JIT en función del escenario de instalación y tarea de Visual Studio.

  • Visual Studio instalado: prueba el depurador JIT.
  • Visual Studio instalado: deshabilitar depurador JIT desde Visual Studio.
  • Visual Studio instalado anteriormente, pero no actualmente: deshabilitar depurador JIT desde el registro de Windows.
  • Visual Studio nunca instalado: impedir la depuración JIT deshabilitando la depuración de scripts, la depuración del lado servidor o la depuración para aplicaciones ASP.NET.

Depuración de scripts

El cuadro de diálogo Depurador JIT puede abrirse cuando la aplicación web encuentra un error, incluso si la configuración no incluye Visual Studio. Esta situación puede producirse si nunca instaló Visual Studio o previamente desinstaló Visual Studio.

En estos escenarios, puede intentar deshabilitar la depuración de scripts o la depuración del lado servidor. Abra el Panel de control de Windows y vaya a la página Redes e Internet>Opciones de Internet.

En el cuadro de diálogo Propiedades de Internet, vaya a la pestaña Opciones avanzadas. Desplácese hasta el grupo Navegación, y seleccione la opción Deshabilitar depuración de scripts.

Depuración del lado servidor

Si hospeda una aplicación web de ASP.NET en Internet Information Services (IIS), deshabilite la depuración del lado del servidor mediante los siguientes pasos:

  1. Abra el Administrador de IIS, y vaya a la Vista de características.
  2. En la sección ASP.NET, haga doble clic o seleccione Compilación de .NET.
  3. En el panel Acciones, seleccione Abrir función.
  4. Para la opción Comportamiento>Depurar, seleccione Falso.

Nota Los pasos específicos son diferentes en versiones anteriores de IIS.

El papel del diseño y de las pruebas

El debugging es una etapa crucial del desarrollo de software por varias razones: garantizar la estabilidad del programa, mejorar el rendimiento, optimizar la experiencia del usuario y asegurar la mantenibilidad.

Un programa con errores puede fallar, lo que puede impactar a los usuarios o degradar la reputación del desarrollador. Algunos bugs pueden causar una ejecución más lenta del programa.

Al corregirlos, el software se vuelve más eficiente. Los bugs pueden hacer que una interfaz sea confusa o inutilizable.

Realizar debugging permite mejorar la calidad de la experiencia ofrecida a los usuarios. Un código fuente bien depurado es más fácil de mantener y evolucionar.

La depuración y la prueba suelen requerir una cantidad de tiempo considerable en comparación con el tiempo dedicado a la primera codificación del programa. Pero no te preocupes, es normal emplear más tiempo en este proceso.

El depurador es una herramienta útil, pero la mejor forma de conseguir programas que funcionen es diseñarlos correctamente, el depurador puede ayudarnos a encontrar errores en la codificación, pero no debe servir para corregir programas mal diseñados.

tags: #el #depurador #no #puede #seguir #ejecutando

Publicaciones populares: