2011-02-24 44 views
15

¿es posible concatenar cadenas durante el preprocesamiento?Concatenación de cadenas con el preprocesador

me encontré con este ejemplo

#define H "Hello " 
#define W "World!" 
#define HW H W 

printf(HW); // Prints "Hello World!" 

Sin embargo, no funciona para mí - imprime "Hola" cuando uso gcc -std=c99

UPD En este ejemplo se parece a trabajar ahora. Sin embargo, ¿es una característica normal del preprocesador c?

Respuesta

36

concatenación de litterals cadena adyacentes no es una característica del preprocesador, es una característica de los idiomas principales (ambos C y C++). Se podría escribir:

printf("Hello " 
     " world\n"); 
10

De gcc online docs:

operador

El preprocesamiento '##' realiza pegar token. Cuando se expande una macro, los dos tokens a cada lado de cada operador '##' se combinan en un único token, que luego reemplaza el '##' y los dos tokens originales en la expansión de macro.

Considere un programa C que interpreta comandos con nombre. Probablemente es necesario que haya una tabla de comandos, tal vez una matriz de estructuras declaradas como sigue:

struct command 
{ 
    char *name; 
    void (*function) (void); 
}; 

struct command commands[] = 
{ 
    { "quit", quit_command }, 
    { "help", help_command }, 
    ... 
}; 

Sería más limpia no tener que dar a cada nombre de la orden dos veces, una vez en la constante de cadena y una vez en la función nombre. Una macro que toma el nombre de un comando como argumento puede hacer que esto sea innecesario. La constante de cadena se puede crear con stringification y el nombre de la función concatenando el argumento con _command. Aquí es cómo se hace:

#define COMMAND(NAME) { #NAME, NAME ## _command } 

struct command commands[] = 
{ 
    COMMAND (quit), 
    COMMAND (help), 
    ... 
}; 
17

Puede concatenar hecho fichas en el preprocesador, pero tenga cuidado porque es difícil. La clave es el operador ##. Si se va a tirar esto en la parte superior de su código:

#define myexample(x,y,z) int example_##x##_##y##_##z## = x##y##z 

continuación, básicamente, lo que hace esto, es que durante el procesamiento previo, que se llevará a cualquier llamada a la macro, tales como los siguientes:

myexample(1,2,3); 

y literalmente se convertirá en

int example_1_2_3 = 123; 

Esto le permite a una tonelada de flexibilidad mientras que la codificación si se usa correctamente, pero no se aplica exactamente cómo se está tratando de usarlo. Sin embargo, con un poco de masaje, puedes hacer que funcione.

Una posible solución para su ejemplo podría ser:

#define H "Hello " 
#define W "World!" 
#define concat_and_print(a, b) cout << a << b << endl 

y luego hacer algo como

concat_and_print(H,W); 
+0

¿Es este un estándar de C++ o solo una característica de gcc? – bibi

+0

En su ejemplo, la concatenación se realiza en tiempo de ejecución no por el preprocesador. –

4

Sólo pensé que añadiría una respuesta que cita la fuente de por qué esto funciona.

La norma C99 §5.1.1.2 define las fases de traducción para el código C. Subsección 6 estados:

  1. cadena adyacente fichas literales están concatenados.

Del mismo modo, en las normas de C++ (ISO 14882) § 2.1 define las fases de la traducción. Aquí Subsección 6 estados:

6 adyacentes cadena ordinaria fichas literales están concatenados. Los tokens literales de cadena ancha adyacentes están concatenados.

Esto es por lo que puede concatenar cadenas simplemente colocándolos adyacentes entre sí:

printf("string"" one\n"); 

>> ./a.out 
>> string one 

La parte de procesamiento previo de la cuestión es simplemente el uso de la directiva #define pre-procesamiento que realiza la sustitución desde el identificador (H) hasta la cadena ("Hello ").