Programación (PRG) PRÁCTICA 5. Depuración de programas

Documentos relacionados
Funciones básicas del depurador

GUIA DE LABORATORIO # 2 ENTORNO DE DESARROLLO Y COMPILACIÓN DE UN PROGRAMA EN C

Dpto. Lenguajes y Ciencias de la Computación E.T.S.I. Telecomunicación. Laboratorio de Programación Uso del depurador en Dev-C++

Fundamentos de Ordenadores. Depurar programas usando Nemiver

Tema 3. Estructuras de control

Tutorial de GDB. Algoritmos y Estructuras de Datos II. Algoritmos y Estructuras de Datos II () Tutorial de GDB 1 / 1

Formatos para prácticas de laboratorio

Guía práctica de estudio: Depuración de programas

Lenguaje C. República Bolivariana de Venezuela Fundación Misión Sucre Aldea Fray Pedro de Agreda Introducción a la Programación III

Entorno de Programación Visual C++ 6.0

ENSAMBLADO DEL PROGRAMA

WHILE Y DO WHILE BREAK EN LENGUAJE C. BUCLES MIENTRAS. FORZAR SALIDA O TERMINACIÓN. EJEMPLO (CU00534F)

Guía de uso del programa AVR-Studio

FUNDAMENTOS DE INFORMÁTICA 1º Ingeniería Industrial

BREVE DESCRIPCIÓN DEL ENTORNO DE PROGRAMACIÓN DE VISUAL LISP

Operadores aritméticos

FACULTAD DE INGENIERÍA

Introducción al Depurador de Dev-C++

Sentencias iterativas

La última versión disponible cuando se redactó este manual era la 5 Beta (versión ), y sobre ella versa este manual.

LENGUAJE DE PROGRAMACION C/C++.

DEPURADOR GDB. Debugging de programas complejos con múltiples archivos.

Esta guía le ayudará a dar los primeros pasos en su aplicación Productor y así poder evaluar su funcionamiento.

Dobles: Es el caso de la instrucción if-else (punto 1.2).

ENTORNO DE DESARROLLO Y COMPILACIÓN DE PELLES C

VB - Access Manual Visual Basic para Aplicaciones del Access 2000

Actividad Algoritmos, Estructura y Programación I. FOR, DO-WHILE

Primeros pasos para utilizar el editor Code::Blocks para C

INSTRUCCIONES CAMPUS. Primer registro

Curso Completo de Visual Basic 6.0

IESTP MOTUPE MICROSOFT WORD 2016

Primeros pasos en Word capítulo 01

CAPÍTULO III MENÚS DEL TURBO PASCAL. File Edit Search Run Compile Debug Tools Options Windows Help [ ] NONAME.PAS

Manual de usuario de Kiva

MANUAL DE USUARIO CARGA DE FICHEROS DE PROCEDIMIENTO -

GCC para plataforma Windows

Capítulo 9 Archivos de sintaxis

El entorno de desarrollo eclipse 3.0.1

Creación/Simulación de un proyecto con ModelSim

Introducción a la Programación

Una función es un miniprograma dentro de un programa. Las funciones contienen varias

ST-8502 ACTUALIZACIÓN ANUAL.

Sage 50c Premium / Standard / Essential. Manual de instalación. SAGE 50c PREMIUM / STANDARD / ESSENTIAL Manual de Instalación

OBJETIVOS ÍNDICE MÓDULO 1: VISUAL BASIC 6.0 PARTE 1ª

1. INTRODUCCIÓN A WRITER

Ayuda. Módulo Manipulación Manual de Cargas (MMC Tarea Simple) CAFERG Aplicación informática para la evaluación de la carga física de trabajo.

Unidad 2. Crear una Presentación (I)

PROF. ANGEL MENDEZ YALLI.

Ministerio de Educación. Base de datos en la Enseñanza. Open Office. Módulo 4: Diseñador de Consultas (+ info)

INTRODUCCIÓN A IMPRESS 1. INTRODUCCIÓN

Práctica 2. Desarrollo de programas. Entrada y salida estándar en C.

Introducción a XCode y Objective-C

Capítulo 4. Estructuras Iterativas

APELLIDOS NOMBRE GRUPO CALIFICACIÓN FECHA

INCIO DE WORD. Mis primeros pasos

Dos de los elementos más importante de cualquier sistema operativo son los archivos y las carpetas.

TECNOLOGÍA DE LA INFORMACIÓN Y COMUNICACIÓN ÁREA SISTEMAS INFORMÁTICOS. Entorno dreamweaver DESARROLLO DE APLICACIONES WEB I

Elementos esenciales de Word

FUNDAMENTOS DE PROGRAMACIÓN Asignatura correspondiente al plan de estudios de la carrera de Ingeniería Informática

TEMA 3: El proceso de compilación, del código fuente al código máquina

Manual del generador del Libro del Edificio. La siguiente imagen muestra la pantalla de trabajo de la herramienta, dividida en tres áreas.

INSTALACIÓN DE VISUAL STUDIO 2010

PARTE 1: Introducción

FUNDAMENTOS DE INFORMÁTICA

DIAGRAMAS DE FLUJO: DFD

CÓMO INICIAR UNA SESIÓN DE CONTROL REMOTO BAJO DEMANDA

MATERIAL PREVIO A LA PRIMERA PRÁCTICA: INTRODUCCIÓN AL ENTORNO WINDOWS INTRODUCCIÓN AL PAQUETE ESTADÍSTICO SPSS

MICROSOFT EXCEL 2007 NIVEL AVANZADO. Contenido

Manual de instalación de R y R Commander

roducción a la programación con el lenguaje C usando el entorno de trabajo Dev-C. Nociones básicas de programación

Unidad 1. Mi primer documento (I)

Transcripción:

Programación (PRG) PRÁCTICA 5. Depuración de programas Facultad de Informática Departamento de Sistemas Informáticos y Computación Universidad Politécnica de Valencia 1. Introducción El objetivo de esta práctica es mostrar el uso de una herramienta muy importante en el proceso de desarrollo de programas: el depurador. Encontrar y solucionar los errores sintácticos (es decir, errores que violan las reglas del lenguaje de programación) es un proceso relativamente sencillo porque el compilador indica la fuente de error y la zona donde puede encontrarse dicho error. Sin embargo, una vez que el programa ha compilado, pueden aparecer una serie de errores más difíciles de encontrar: los errores semánticos o lógicos. Dichos errores hacen que el programa se comporte de forma inesperada, o que devuelva resultados erróneos. Algunos de dichos errores son muy difíciles de encontrar. En estos casos hay que averiguar dónde se produce el error y por qué. En esta práctica se ofrecen algunos consejos útiles para utilizar el depurador para encontrar dichos errores. 2. Qué es un depurador? Hasta ahora, la única forma de realizar la traza de un programa era hacerla a mano o insertar en el código fuente impresiones intermedias. Veámoslo con un ejemplo. Dado el siguiente programa: #include <stdio.h> #define N 10 void main() { int i, a; a=0; 1

for (i=1;i<=n;i++) { a+=i*i; printf("%d\n",a); Ejercicio. Qué hace el programa? Realiza una traza de la ejecución. El resultado del ejercicio anterior debe ser parecido a la siguiente tabla: i i i a 1 1 1 2 4 5 3 9 14 4 16 30 5 25 55 6 36 91 7 49 140 8 64 204 9 81 285 10 100 385 Una opción a la traza manual del programa es añadir líneas auxiliares al código inicial, que muestren por pantalla los resultados intermedios: #include <stdio.h> #define N 10 void main() { int i, a; a=0; printf(" i i*i a\n"); /* Traza */ printf("--------------\n"); /* Traza */ for (i=1;i<=n;i++) { a+=i*i; printf("%4d %4d %4d\n", i, i*i, a); /* Traza */ printf("%d\n",a); 25 de noviembre de 2002 Página 2 de 13

Y ejecutar el nuevo código: i i*i a -------------- 1 1 1 2 4 5 3 9 14 4 16 30 5 25 55 6 36 91 7 49 140 8 64 204 9 81 285 10 100 385 385 Esta tarea se puede realizar de forma automática utilizando un depurador. Un depurador, fundamentalmente, permite: 1. Ejecutar un programa instrucción a instrucción o detenerse en un punto dado. 2. Una vez detenida momentáneamente la ejecución de un programa, se puede consultar el estado de las variables. 3. Examinar las llamadas y retornos de funciones. 4. Consultar los registros de activación existentes en la pila en un momento dado de la ejecución del programa. En el apartado siguiente se muestra cómo utilizar el entorno gráfico del depurador. Aviso!! Para poder depurar el programa, éste ha de ser compilado con el parámetro -g, caso de tratarse de un programa en C y el compilador GNU gcc. Ejercicio Compila el programa ejemplo1.c con la opción -g : [carraca@pc011 p5]$ gcc ejemplo1.c -o ejemplo1 -Wall -g 3. Qué es DDD? El depurador que se explica a continuación es el GNU DDD (Display Data Debugger), un entorno gráfico del depurador GDB The GNU Source- Level Debugger, que permite depurar código generado en C, C++, Java, 25 de noviembre de 2002 Página 3 de 13

Modula-2, Modula-3, Pascal, Chill, Ada, Fortran y ensamblador. 1 Para conocer más a fondo este entorno o el depurador, se puede consultar: Manual del entorno DDD (http://www.gnu.org/manual/ddd/index. html). Manual del depurador GDB (http://www.gnu.org/manual/gdb-5. 1.0.1/gdb.html). Artículo en Dr. Dobb s Journal de uno de los autores del entorno, Andreas Zeller [Zel01], artículo de José María Laveda en LinuxFocus [Lav98]. Ejercicio Invoca al depurador con ddd y el nombre del ejecutable del programa ejemplo1.c. Obtendrás la ventana de la Figura 1. [carraca@pc011 p5]$ ddd ejemplo1 Figura 1: Ventana que se obtiene al invocar el depurador ddd con el ejecutable ejemplo1. 1 En realidad, el entorno gráfico DDD puede ser utilizado con otros depuradores aparte del GDB, tales como DBX, WDB, Ladebug, JDB, XDB, Perl debugger, o Python debugger. 25 de noviembre de 2002 Página 4 de 13

3.1. Aspecto del entorno En la Figura 1 se puede observar que la ventana está dividida en dos zonas: la zona del código (Source window): muestra el código fuente (en nuestro caso, el fuente ejemplo1.c); la zona inferior (Debugger Console): se corresponde con la ventana del depurador, y en ella se pueden introducir los comandos directamente al depurador gdb. La barra de tareas o ventana flotante que aparece permite controlar la ejecución del programa en todo momento. 3.2. Obteniendo ayuda En el entorno DDD se puede obtener información sobre las acciones en curso, o sobre cómo realizar alguna tarea de múltiples formas, por ejemplo, si se deja el puntero del ratón encima de una variable o de cualquier botón del entorno aparecerá un diálogo mostrando información sobre el mismo; en la parte inferior de la ventana hay una línea de estado sobre lo que se está haciendo y su resultado; en la parte derecha de la barra de menús hay un elemento desplegable con la ayuda disponible (opción Help ); pulsando F1 sobre cualquier menú (véase la Figura 2). En la ventana del depurador podemos introducir help para una ayuda general o sobre cualquier otro comando. Ejercicio Comprueba cómo funcionan las ayudas del depurador sobre los distintos menús. Fíjate en lo que puedes hacer con cada comando de los distintos menús. 4. Una sesión con el DDD Una vez invocado el DDD con el ejecutable a depurar, el código fuente del programa aparece en el área correspondiente. A partir de este momento ya se puede navegar por el código fuente, obtener el valor y definición de las variables, ejecutar el programa controlando su evolución... 25 de noviembre de 2002 Página 5 de 13

Figura 2: Ayuda sobre el menú Program (con F1 ). 4.1. Puntos de ruptura Normalmente lo primero que se hace es establecer uno o varios puntos de ruptura (breakpoint), con el fin de poder detener la ejecución del programa en algún punto de interés. En el ejemplo que se está siguiendo, se pondrá un punto de ruptura en la línea correspondiente a: Para ello, a+=i*i; 1. se coloca el puntero del ratón en la parte izquierda de la línea en la que se desea poner el punto de ruptura: ejemplo1.c:9, y 2. se selecciona la opción Set Breakpoint que aparece en el menú al pulsar el botón derecho del ratón o pulsando el botón Break en la barra de herramientas. El depurador indica que se ha fijado el punto de ruptura mediante una pequeña señal en la línea marcada (véase la Figura 3). Otra forma de establecer los puntos de ruptura es haciendo doble clic a la izquierda de la instrucción donde se desea parar la ejecución. También con el ratón se pueden arrastrar puntos de ruptura de una línea a otra. Una vez se inicie la ejecución y se llegue al punto de ruptura, se podrá estudiar el estado de las variables definidas en el programa mediante las opciones que se explican más adelante. 25 de noviembre de 2002 Página 6 de 13

Figura 3: Punto de ruptura en la línea 9. 4.2. Puntos de ruptura condicionales y lista de puntos de ruptura se pueden establecer puntos de ruptura que se activen únicamente cuando se cumpla una cierta condición. Para ello, hay que pulsar con el botón derecho del ratón sobre la marca del punto de ruptura y seleccionar la opción Properties.... Entonces aparecerá la ventana que muestra la Figura 4. Figura 4: Propiedades de un punto de ruptura. Dentro de dicha ventana, en el cuadro de texto Condition se puede escribir una condición válida con la sintaxis de C (por ejemplo, a>=3). Cuando la ejecución pase por la línea del punto de ruptura, únicamente se detendrá si la condición es cierta. Dentro del mismo cuadro de diálogo, 25 de noviembre de 2002 Página 7 de 13

también se permite deshabilitarlo temporalmente ( Disable ) o permanentemente ( Delete ). Por último, si se pulsa el botón marcado como Temp, el punto de ruptura se convertirá en temporal, y únicamente funcionará una vez. La opción Breakpoints del menú Source permite mostrar una lista de todos los puntos de ruptura definidos en el programa, como muestra la Figura 5, y editar sus propiedades, habilitarlos, deshabilitarlos o borrarlos. En el manual de DDD se pueden encontrar más formas de manejo de puntos de ruptura. Figura 5: Lista de los puntos de ruptura definidos. 4.3. Ejecución del programa Existen distintas formas de ejecutar un programa: Run ejecuta el programa (desde el principio) hasta un punto de ruptura. Es decir, sea cual sea el estado de la ejecución del programa, Run comienza la ejecución desde el principio y se para en el primer punto de ruptura. Step ejecuta el programa una línea más (paso a paso), esto es, si se hace una llamada a una función, se recorrerán las líneas de esta. Next ejecuta la siguiente línea. Cont permite continuar con la ejecución del programa tras el punto de ruptura. Kill, Interrupt y Abort permiten interrumpir el programa depurado. Finish termina la función actual y muestra el valor devuelto. Siguiendo con el ejemplo, al pulsar Run, comienza la ejecución de ejemplo1 hasta que se alcanza el punto de ruptura. Dicha información aparece en la ventana del depurador y la línea actual donde se encuentra la 25 de noviembre de 2002 Página 8 de 13

ejecución (es decir, la siguiente línea que se va a ejecutar) se indica con una flecha verde (véase la Figura 6). Figura 6: Consulta de variables (mediante la opción Display ). Una vez que se ha detenido la ejecución del programa se pueden consultar los valores de las variables. Para ello, se puede dejar el puntero del ratón encima de la variable del código fuente para obtener su valor actual en la línea de estado (también aparece una ventana con el valor de la variable). Si se pulsa el botón derecho del ratón sobre el nombre de una variable, aparece un submenú con las siguientes opciones: 1. Print a : permite obtener el valor de la variable a (en la ventana inferior del depurador). 2. Display a : permite mostrar visualmente el valor de la variable a en la ventana superior ( área de dibujo ). Esta opción es especialmente útil cuando se desea visualizar vectores, listas, etc... En la Figura 6 se puede ver el valor de la variable a en el área de dibujo. El valor de la variable se actualiza automáticamente cada vez que el programa se detiene en un punto de ruptura. 3. Con What is se puede conocer la estructura o tipo de variable señalada (en la ventana inferior del depurador). En la Figura 6 se muestra la información del tipo de la variable a en el área del depurador. 4. Lookup permite la búsqueda de ocurrencias de la variable. 25 de noviembre de 2002 Página 9 de 13

5. Break at y Clear at permiten el manejo de los puntos de ruptura. Para continuar la ejecución a partir de un punto de ruptura, y ejecutar la línea actual, se puede pulsar el botón Next. La flecha avanza hasta la línea siguiente. El botón Step realiza la misma acción: ejecutar la siguiente instrucción. La diferencia entre una opción y otra aparece cuando se va a ejecutar una llamada a una función. En el caso de Next ejecuta toda la función, parando la ejecución en la línea que aparece a continuación de la llamada, y Step detiene la ejecución en la primera instrucción de la función. Para continuar la ejecución hasta una línea determinada se puede pulsar el botón derecho del ratón sobre la línea donde parar y elegir la opción Continue Until Here. El botón Cont reanuda la ejecución del programa hasta el siguiente punto de ruptura (o hasta que se acabe). Finalmente, para salir del entorno, se puede ejecutar la opción Program Exit o pulsando Ctlr+Q. 5. Consejos finales Antes de empezar a depurar, deberás tener un código fuente limpio, con una instrucción por línea para poder poner puntos de ruptura sin problemas, y bien indentando para poder visualizar claramente los bloques que forman el programa. Para formatear automáticamente un programa puedes utilizar el programa indent 2. Dicho programa funciona del siguiente modo: [carraca@pc011 p5]$ indent dificil.c Si inicialmente el fichero dificil.c contiene el siguiente código: #include <stdio.h> int main() { int a,b,c,i; printf("escribe un número: "); scanf("%d",&b); a=0; c=0; while (a<b) {a++; for (i=1;i<=2;i++) c++; printf("\nel número es %d y el doble es %d\n",a,c); 2 Normalmente en Linux ya está instalado. Para instalarlo en Windows, bájate los paquetes indent, gettext y LibIconv de http://www.kefk.net/open_source/fs/ GnuWin32/ y copia los archivos que están dentro de los directorios bin de esos paquetes en un directorio de tu PATH (por ejemplo, en c:\mingw\bin si tienes ahí instalado el compilador. 25 de noviembre de 2002 Página 10 de 13

Después de ejecutar la orden anterior, el fichero quedará como muestra la Figura 7. #include <stdio.h> int main () { int a, b, c, i; printf ("Escribe un número: "); scanf ("%d", &b); a = 0; c = 0; while (a < b) { a++; for (i = 1; i <= 2; i++) c++; printf ("\nel número es %d y el doble es %d\n", a, c); Figura 7: Código fuente reformateado por indent. A la hora de utilizar un depurador para encontrar un fallo en un programa, debes aplicar un método lógico, paso por paso [Got97]. Lo primero es aislar el error. Si el programa acaba inesperadamente (por ejemplo, con un mensaje de Violación de segmento), es prioritario detectar qué instrucción está produciendo ese acceso no permitido. Para ello, se pueden introducir distintos puntos de ruptura en el programa, y lanzar la ejecución. Cuando, al pasar de un punto de ruptura al siguiente se produce el fallo del programa, ya se ha encontrado el bloque de código problemático. Cuando el programa tiene varias funciones, es útil comprobar el estado de las variables del programa antes y después de cada llamada a función. Esto permite detectar qué función falla. Una vez que se ha detectado el bloque de código o función donde se encuentra el error, es necesario ejecutar paso a paso las instrucciones de ese bloque. Dicha ejecución deberá revelar la instrucción transgresora, y el valor de las variables involucradas. Cuando estés depurando paso a paso un programa, deja visibles permanentemente las variables de interés. Cada vez que avances una instrucción, dichas variables se actualizarán y podrás ver su evolución. 25 de noviembre de 2002 Página 11 de 13

Para finalizar, varios consejos: Una vez que hayas acabado de escribir un programa y compile, somételo a pruebas de robustez. No pruebes los casos que sabes que funcionan, sino aquellos casos particulares que pueden suponer un problema al programa (números negativos, cadenas vacías, números repetidos, etc). Ningún programa da saltos aleatorios. Si para ir del punto A al punto B tienes que pasar por el C, y has empezado en A y has acabado en C, ten seguro que B se ha ejecutado. Si te parece que no se ha ejecutado (por ejemplo, si B es un bucle que imprime algo por pantalla y no ha sacado nada), es porque hay alguna razón (por ejemplo, que la guarda del bucle está mal escrita). No asumas que una variable vale lo que crees que vale. Visualiza su valor y comprueba lo que vale realmente. Apréndete los atajos de teclado para depurar el código. Irás más rápido que con el ratón. No le eches la culpa al ordenador, al compilador, a Linux o a Bill Gates. El 99,9% de las veces será culpa tuya. Ejercicios propuestos 1. Dado el siguiente programa: #include <stdio.h> int main() { int i,j,k,n,p; p=0; printf("escribe un número: "); scanf("%d",&n); for (i=0;i<n;i++) for (j=0;j<n;j++) for (k=0;k<n;k++) { if (k%2==0) if (i*j<n i+j>k) p++; printf("resultado: %d\n",p); return 0; 25 de noviembre de 2002 Página 12 de 13

Suponiendo que el usuario ha introducido un 10 por teclado: a) Indica cuánto vale la variable p, cuando i=5, j=5 y k=5. b) Calcula cuántas veces cambia de valor la variable p cuando i=5 y j=3. c) Indica el valor de las variables i, j y k en el momento en que p toma el valor de 300. 2. Encuentra los errores en el programa que se encuentra en el fichero /misc/practicas/asignaturas/prgfi/p5/had_mal.c, haciendo uso del depurador. El programa debería pedir una letra al usuario, y mostrar todas las palabras de una lista interna que empiecen por dicha letra. Para ello, busca una palabra válida mediante una búsqueda dicotómica, y luego secuencialmente, a partir de ella, la primera y última palabra buscada. La lista original está ordenada. Una vez que creas haber encontrado todos los errores, prueba el comportamiento del programa para las letras a, z, ~n, o y 8. 3. Encuentra los errores en el programa que se encuentra en el fichero /misc/practicas/asignaturas/prgfi/p5/ahorcado_mal.c, haciendo uso del depurador. El programa plantea al usuario el juego del ahorcado. En primer lugar pide un número al usuario para inicializar el generador de números aleatorios. Después inicia el juego del ahorcado. Una cadena de caracteres indica las letras que quedan por descubrir. El usuario puede introducir letras, y según acierta o no, el programa descubre las letras de la palabra desconocida o va reduciendo la vida del jugador, completando la palabra AHORCADO. El jugador gana si descubre la palabra y pierde si es ahorcado. Cuando acaba un juego el programa pregunta si se quiere jugar con otra palabra diferente o acabar la ejecución. Referencias [Got97] Byron Gottfried. Programación en C. Mc. Graw Hill, 1997. [Lav98] José María Laveda. Depurando código con ddd. Linux FOCUS, January 1998. http://www.linuxfocus.org/castellano/january1998/article20.html [Zel01] Andreas Zeller. Visual Debugging with DDD. Dr. Dobb s Journal, March 2001. http://www.ddj.com/articles/2001/0103/ 25 de noviembre de 2002 Página 13 de 13