Acabo de terminar de programar un gran proyecto en C. Tengo mucho código de depuración (printfs y otras cosas dentro del código). Ahora, esas declaraciones de depuración son una sobrecarga de rendimiento y quiero eliminarlas, pero son muy útiles en el futuro para solucionar problemas. ¿Cuáles son las mejores prácticas para colocar el código de depuración en el código base? Tengo muchas opciones.
Use un argumento de terminal (digamos -d ) para especificar si el ejecutable debe ejecutarse en modo de depuración o no. La ventaja es que el código no cambiará más adelante. La desventaja es que el código estará lleno de condicionales para verificar si el programa está en modo de depuración o no.
La otra solución es usar algunas macros de C para la depuración. No entiendo muy bien cómo funciona esto. Parece que definirías d_printf que sería printf si estás en modo de depuración y nada si no lo estás. Pero supongo que esto requerirá volver a compilar el código cada vez que cambie de un modo de depuración a un modo de no depuración.
¿Pueden los profesionales de C con experiencia asesorar sobre cuáles son las mejores prácticas?
Personalmente, me gusta la capacidad de activar la depuración sin necesidad de volver a compilar para habilitar la depuración.
Normalmente tengo un método de depuración que verifica un argumento de línea de comando o una variable de entorno y genera mensajes <= una prioridad determinada.
p.ej
void debug(int level, char *msg) { if (level <= currentDebugLevel) { printf("%s\n", msg); /* or to stderr, or to file } } Puede convertirlo en una función varargs para que pueda usar lo mismo que printf
¿ Mejores prácticas? No use printf() o fprintf() para stdout o stderr redirigido a un archivo, especialmente para procesos de larga duración. Esos métodos pueden ser adecuados para la depuración casual, pero tienen serias deficiencias para los procesos de larga duración que pueden producir grandes cantidades de datos.
Si usa printf() o fprintf() para dichos flujos o archivos fijos, se vincula a esos archivos y no puede mover fácilmente el registro a otro archivo, o no puede mover el flujo de datos en absoluto. dependiendo de muchos detalles. Por lo tanto, sin reiniciar su proceso, no puede mover el archivo de registro como parte de un proceso de caducidad del archivo de registro ni puede truncar o eliminar el archivo si llena su espacio en disco.
Y no hay necesidad de reinventar mal la rueda. Casi todos los sistemas operativos proporcionan una capacidad de registro diseñada para escalar y cumplir con el requisito de que un archivo de registro sea separable del proceso que realiza el registro. Los sistemas Unix/Linux proporcionan syslog (o rsyslog debajo del capó), el sistema Windows tiene la API EventLog . Una vez que aprende a usarlos y configurarlos, son mucho más fáciles de configurar, codificar y usar que casi cualquier producto de registro adicional.
Además, defina macros de depuración usando los valores predefinidos __func__ , __FILE__ y __LINE__ en su salida de depuración:
#define DEBUGLOG( level, ... ) \ do \ { \ if ( ( level ) < currentDebugLevel ) \ { \ debugFuncCall( ( level ), __func__, __FILE__, __LINE__, __VA_ARGS__ ); \ } \ } \ while ( 0 ) Eso proporcionará datos de depuración muy útiles con muy poco esfuerzo. Puede definir macros de depuración simples como ENTER_METHOD( args...) y EXIT_METHOD( retval ) macros que en el nivel apropiado de depuración le permitirán rastrear todo lo que hace su programa.