Macro DEBUG
Un comentario sobre la Depuracion en C
Cuando se programa, normalmente uno no se da cuenta de lo grande que es un código, o de o complejo que es un programa, hasta que se cuelga, y hay que depurarlo. La técnica habitual consiste en ir poniendo printf en sitios estratégicos para ver que está haciendo nuestra criatura, pero el problema es que pecamos de inconsistentes. Un mensaje puede decir “Leyendo puntero” y otro decir “Esto no debería de salir nunca”, y si no sabemos exactamente donde está esa cadena, nos quedamos donde estábamos.
Llevaba tiempo queriendo homogeneizar las cadenas que uso para depurar los programas, sobre todo los muy grandes. Había visto en algunos códigos de GNU unas macros que encapsulaban un printf, de forma que tu ponías algo como DEBUG(“Tutu vale %d“, tutu), y se transformaba en algo como “Depuración, línea 55, archivo titi.c: Tutu vale 3“.
Incluso en otras que he visto, se puede especificar un nivel de depuración (si estás en depuración 1 sólo muestras las llamadas a funciones, pero si estás en 500 muestras todas las asignaciones, y cosas así). Sin embargo, hay un problema, ¿como pasas un número de parámetros variable a una macro?
Un recordatorio sobre las Macros en C
Recordemos que una macro es una cadena que interpreta el preprocesador, haciendo una sustitución sencilla de esa cadena por la equivalencia que hayamos definido. Si la macro permite parámetros, simplemente se sustituye el parámetro por el valor en la aparición de la cadena. Por ejemplo, si tenemos la macro
#define SUMAR(A,B) a + b
y nos encontramos con:
int z,x,y;
z = SUMAR(x,y);
El preprocesador cambiará la línea anterior por:
int z,x,y;
z = x + y;
En ese sentido, el printf nos presenta un problema, porque los argumentos que se le pasan, son variables. Podemos hacer printf(“tutu %d tete %f titi %s\n”, tutu, tete, titi) o también podemos hacer simplemente printf(“wisconsin\n”), por lo tanto, no podemos definir una macro concreta para un printf, porque no sabríamos los parámetros que habría que pasarle.
¿Por qué se llama entonces este post Macro Debug?
Porque sí se puede… pero sólo desde que salió el estándar C99. Acorde, entre otras pocas, con la wikipedia, en el estándar de C99 se implementaron por primera vez las macros con argumentos variables, justamente para poder hacer macros que encapsulen a un printf y similares, sin tener que hacer funciones específicas.
Hacerlo es bastante sencillo:
#define DEBUG(FILENAME,STRING,...) printf("DEBUG: " FILENAME " " STRING, __VA_ARGS)
Cuando usemos esa macro, por ejemplo, haciendo
DEBUG(__FILE__,"Tutu %d tete %c", tutu, tete)
el preprocesador nos generará la línea:
printf("DEBUG: main.c Tutu %d tete %c", tutu, tete);
Como podemos ver, el preprocesador extiende automáticamente las comillas para ocupar todos los parámetros consecutivos. Usando esta función (con los parámetros que se quieran poner), se puede tener una salida homogénea para la depuración del código. Incluso, si no queremos generar código de depuración pero no queremos borrar todas las líneas de debug porque pueden hacernos falta en un futuro, podemos hacer:
#ifdef I_WANT_DEBUG
#define DEBUG(FILENAME,STRING,...)
printf("DEBUG: " FILENAME " " STRING, __VA_ARGS)
#else
#define DEBUG(FILENAME,STRING,...) ;
#endif
Usando el código anterior, si está definida la macro I_WANT_DEBUG, generaremos el código de printf, de lo contrario, generaremos una sentencia vacía.
Buena suerte a todos.