9.6. Más características del preprocesador

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.

9.6.1. Encolado de símbolos

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.