En un entorno ideal, habrá un depurador excelente disponible que hará que el comportamiento de su programa sea transparente y podrá descubrir cualquier error rápidamente. Sin embargo, muchos depuradores tienen puntos débiles, y eso hará que tenga que añadir trozos de código a su programa que le ayuden a entender qué está pasando. Además, puede que para la plataforma para la que esté desarrollando (por ejemplo en sistemas empotrados, con lo que yo tuve que tratar durante mis años de formación) no haya ningún depurador disponible, y quizá tenga una realimentación muy limitada (por ejemplo, un display de LEDs de una línea). En esos casos debe ser creativo a la hora de descubrir y representar información acerca de la ejecución de su programa. Esta sección sugiere algunas técnicas para conseguirlo.
Si incrusta código de depuración en un programa, puede tener problemas. Empezará a tener demasiada información, que hará que los errores sean difíciles de aislar. Cuando cree que ha encontrado el error empieza a quitar el código de depuración, sólo para darse cuenta de que necesita ponerlo de nuevo. Puede resolver estos problemas con dos tipos de banderas: banderas de depuración del preprocesador y banderas de depuración en ejecución.
Usando el preprocesador para definir (con #define) una o más banderas de depuración (preferiblemente en un fichero de cabecera), puede probar una bandera usando una sentencia #ifdef e incluir condicionalmente código de depuración. Cuando crea que la depuración ha terminado, simplemente anule la bandera con #undef y el código quedará eliminado automáticamente (y reducirá el tamaño y sobrecarga del fichero ejecutable).
Es mejor decidir los nombres de las banderas de depuración antes de empezar a construir el proyecto para que los nombres sean coherentes. Las banderas del preprocesador tradicionalmente se distinguen de las variables porque se escriben todo en mayúsculas. Un nombre habitual es simplemente DEBUG (pero tenga cuidado de no usar NDEBUG, que está reservado en C). La secuencia de sentencias podría ser:
#define DEBUG // Probably in a header file //... #ifdef DEBUG // Check to see if flag is defined /* debugging code here */ #endif // DEBUG
La mayoría de las implementaciones de C y C++ también le permitirán definir y eliminar banderas (con #define y #undef) desde línea de comandos, y de ese modo puede recompilar código e insertar información de depuración con un único comando (preferiblemente con un makefile, una herramienta que será descrita en breve). Compruebe la documentación de su entorno si necesita más detalles.
En algunas situaciones es más conveniente activar y desactivar las banderas de depuración durante la ejecución del programa, especialmente activándolas al arrancar el programa desde la línea de comandos. Con programas grandes resulta pesado recompilar sólo para insertar código de depuración.
Para activar y desactivar código de depuración dinámicamente cree banderas booleanas.
//: C03:DynamicDebugFlags.cpp #include <iostream> #include <string> using namespace std; // Debug flags aren't necessarily global: bool debug = false; int main(int argc, char* argv[]) { for(int i = 0; i < argc; i++) if(string(argv[i]) == "--debug=on") debug = true; bool go = true; while(go) { if(debug) { // Debugging code here cout << "Debugger is now on!" << endl; } else { cout << "Debugger is now off." << endl; } cout << "Turn debugger [on/off/quit]: "; string reply; cin >> reply; if(reply == "on") debug = true; // Turn it on if(reply == "off") debug = false; // Off if(reply == "quit") break; // Out of 'while' } } ///:~
Listado 3.62. C03/DynamicDebugFlags.cpp
Este programa sigue permitiéndole activar y desactivar la bandera de depuración hasta que escriba quit para indicarle que quiere salir. Fíjese en que es necesario escribir palabras completas, no sólo letras (puede abreviarlo a letras si lo desea). Opcionalmente, también se puede usar un argumento en línea de comandos para activar la depuración al arrancar - este argumento puede aparecer en cualquier parte de la línea de comandos, ya que el código de arranque en main() busca en todos los argumentos. La comprobación es bastante simple gracias a la expresión:
string(argv[i])
Esto toma el array de caracteres argv[i] y crea un string, el cual se puede comparar fácilmente con lo que haya a la derecha de ==. El programa anterior busca la cadena completa --debug=on. También puede buscar --debug= y entonces ver qué hay después, para proporcionar más opciones. El Volumen 2 (disponible en www.BruceEckel.com) contiene un capítulo dedicado a la clase string Estándar de C++.
Aunque una bandera de depuración es uno de los relativamente pocos casos en los que tiene mucho sentido usar una variable global, no hay nada que diga que debe ser así. Fíjese en que la variable está escrita en minúsculas para recordar al lector que no es una bandera del preprocesador.