Antes, se dijo que casi siempre se prefiere
usar funciones inline en lugar de macros del preprocesador. Las
excepciones aparecen cuando necesita usar tres propiedades especiales
del preprocesador de C (que es también el preprocesador de C++):
[FIXME(hay más):cadenización?]
(stringizing), concatenación de cadenas, y
encolado de símbolos (token
pasting). Stringizing, ya
comentado anteriormente en el libro, se efectúa con la directiva
#
y permite tomar un identificador y
convertirlo en una cadena de caracteres. La concatenación de
cadenas tiene lugar cuando dos cadenas adyacentes no tienen
puntuación, en cuyo caso se combinan. Estas dos propiedades son
especialmente útiles cuando se escribe código de depuración. Así,
#define DEBUG(x) cout << #x " = " << x << endl
Esto imprime el valor de cualquier variable. Puede conseguir también una traza que imprima las sentencias tal como se ejecutan:
#define TRACE(s) cerr << #s << endl; s
El #s
cadeniza la
sentencia para la salida, y la segunda s
hace
que la sentencia se ejecute. Por supuesto, este tipo de cosas
pueden causar problemas, especialmente bucles for
de una
única línea.
for(int i = 0; i < 100; i++) TRACE(f(i));
Como realmente hay dos sentencias en la macro
TRACE()
, el bucle for
de
una única línea ejecuta solo la primera. La solución es reemplazar
el punto y coma por una coma en la macro.
El encolado de símbolos, implementado con la directiva
##
, es muy útil cuando se genera
código. Permite coger dos identificadores y pegarlos juntos
para crear un nuevo identificador automáticamente. Por
ejemplo,
#define FIELD(a) char* a##_string; int a##_size class Record { FIELD(one); FIELD(two); FIELD(three); // ... };
Cada llamada a la macro FIELD()
crea un
identificador para una cadena de caracteres y otro para la
longitud de dicha cadena. No solo es fácil de leer, también
puede eliminar errores de codificación y facilitar el
mantenimiento.