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 puede requerir tenga que añadir trozos de código a su programa que le ayuden a entender que 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 coloca el código de depuración mezclado con un programa, tendrá 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 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 utilice
#undef
la bandera 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 contruir el proyecto para que los nombres
sean consistentes. 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ías 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 cuando el programa se ejecuta usando 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 que es necesario escribir palabras completas, no solo letras
(puede abreviarlo a letras si lo desea). Opcionalmente, también se puede usar un
argumento en línea de comandos para comenzar la depuración - este argumento
puede aparecer en cualquier parte de la línea de comando, ya que el código de
activación en main()
busca en todos los argumentos. La
comprobación es bastante simple como se ve en la expresión:
string(argv[i])
Esto toma la cadena 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 que 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.