2011-06-28 18 views
16

¿Qué significa esta línea? Especialmente, ¿qué significa ##?¿Qué significa ## en a #define?

 
#define ANALYZE(variable, flag)  ((Something.##variable) & (flag)) 

Editar:

Un poco confundido todavía. ¿Cuál será el resultado sin ##?

+0

también ver: http://stackoverflow.com/questions/1597007/creating-c-macro-with-and-line-token-concatenation-with-positioning-macro – sharkin

Respuesta

8

A little bit confused still. What will the result be without ##?

Por lo general, no notará ninguna diferencia.Pero hay es una diferencia. Supongamos que Something es de tipo:

struct X { int x; }; 
X Something; 

y mirar:

int X::*p = &X::x; 
ANALYZE(x, flag) 
ANALYZE(*p, flag) 

Sin operador de concatenación símbolo ##, se expande a:

#define ANALYZE(variable, flag)  ((Something.variable) & (flag)) 

((Something. x) & (flag)) 
((Something. *p) & (flag)) // . and * are not concatenated to one token. syntax error! 

con la concatenación señal se expande a:

#define ANALYZE(variable, flag)  ((Something.##variable) & (flag)) 

((Something.x) & (flag)) 
((Something.*p) & (flag)) // .* is a newly generated token, now it works! 

Es importante recordar que el preprocesador opera en tokens de preprocesador, , no en texto. Entonces, si desea concatenar dos tokens, debe decirlo explícitamente.

10

## se llama concatenación de token, que se utiliza para concatenar dos tokens en una macro invocación.

ver esto:

+3

De hecho, se llama concatenación de token. ¡No creo que la documentación para el compilador IBM AIX C/C++ sea la mejor referencia! –

+0

@David: Agregué esto a mi respuesta. Gracias :-) – Nawaz

+0

@David: No dije IBM AIX C/compilador de C++ es la mejor referencia. La mejor referencia no es otra cosa que el Estándar en sí mismo. Pero damos enlaces a otros sitios de todos modos, incluidos los temas en stackoverflow. – Nawaz

3

Según Wikipedia

Token concatenation, also called token pasting, is one of the most subtle — and easy to abuse — features of the C macro preprocessor. Two arguments can be 'glued' together using ## preprocessor operator; this allows two tokens to be concatenated in the preprocessed code. This can be used to construct elaborate macros which act like a crude version of C++ templates.

Comprobar Token Concatenation

8

Una parte muy importante es que esta concatenación símbolo sigue unas reglas muy especiales :

p. Ej. IBM doc:

  • La concatenación tiene lugar antes de que se expandan las macros en los argumentos.
  • Si el resultado de una concatenación es una válida nombre de macro, que está disponible para el reemplazo más aún si aparece en un contexto en el que normalmente no estará disponible.
  • Si más de uno y/o # operador ## operador aparece en la lista de reemplazo de una definición de macro, el orden de evaluación de los operadores no se define.

Ejemplos son también muy auto explicando

#define ArgArg(x, y)   x##y 
#define ArgText(x)   x##TEXT 
#define TextArg(x)   TEXT##x 
#define TextText    TEXT##text 
#define Jitter    1 
#define bug     2 
#define Jitterbug    3 

Con salida:

ArgArg(lady, bug) "ladybug" 
ArgText(con) "conTEXT" 
TextArg(book) "TEXTbook" 
TextText "TEXTtext" 
ArgArg(Jitter, bug)  3 

Fuente es la documentación de IBM. Puede variar con otros compiladores.

Para su línea:

Se concatena el atributo variable para el evento "Algo". y hace referencia a una variable que está lógicamente anded, lo que da como resultado si Something.variable tiene un indicador establecido.

Así un ejemplo para mi último comentario y su pregunta (compileable con g ++):

// this one fails with a compiler error 
// #define ANALYZE1(variable, flag)  ((Something.##variable) & (flag)) 
// this one will address Something.a (struct) 
#define ANALYZE2(variable, flag)  ((Something.variable) & (flag)) 
// this one will be Somethinga (global) 
#define ANALYZE3(variable, flag)  ((Something##variable) & (flag)) 
#include <iostream> 
using namespace std; 

struct something{ 
int a; 
}; 

int Somethinga = 0; 

int main() 
{ 
something Something; 
Something.a = 1; 

if (ANALYZE2(a,1)) 
    cout << "Something.a is 1" << endl; 
if (!ANALYZE3(a,1)) 
    cout << "Somethinga is 0" << endl; 
     return 1; 
}; 
+0

¿Cuál será el resultado sin '##'? –

+0

por lo que mi prueba dio como resultado. Gcc se queja de 'a. ## b'. 'a ## b' evalúa el derecho a un global. 'a.b' también evalúa el derecho a una variable dentro de la instancia struct a. – fyr

+0

Agregué un ejemplo como adición. – fyr

2

Vamos a considerar un ejemplo diferente:

considerar

#define MYMACRO(x,y) x##y 

sin la ##, claramente el preprocesador no puede ver x y y como señales separadas, ¿verdad?

En su ejemplo,

#define ANALYZE(variable, flag)  ((Something.##variable) & (flag)) 

## simplemente no es necesario, ya que no están haciendo ningún nuevo identificador. De hecho, el compilador emite "error: pegar". "Y" variable "no proporciona un token de preprocesamiento válido"

2

Esta no es una respuesta a su pregunta, solo una publicación de CW con algunos consejos para ayudarlo a explorar el preprocesador tú mismo.

El paso de preprocesamiento se realiza realmente antes de que se compile cualquier código real. En otras palabras, cuando el compilador comienza a construir su código, no quedan declaraciones #define ni nada por el estilo.

Una buena forma de entender qué hace el preprocesador con su código es obtener la salida preprocesada y observarla.

Se trata de cómo hacerlo para Windows:

Crear un archivo simple llamado test.cpp y la puso en una carpeta, por ejemplo c: \ temp. mina se parece a esto:

#define dog_suffix(variable_name) variable_name##dog 

int main() 
{ 
    int dog_suffix(my_int) = 0; 
    char dog_suffix(my_char) = 'a'; 

    return 0; 
} 

No es muy útil, pero simple. Abra el símbolo del sistema de Visual Studio, vaya a la carpeta y ejecutar el siguiente orden:

c:\temp>cl test.cpp /P 

lo tanto, es el compilador de su carrera (cl.exe), con su archivo, y la opción/P indica al compilador que almacena la salida preprocesada a un archivo.

Ahora en la carpeta al lado de test.cpp encontrará la prueba.i, que para mí es el siguiente:

#line 1 "test.cpp" 


int main() 
{ 
    int my_intdog = 0; 
    char my_chardog = 'a'; 

    return 0; 
} 

Como se puede ver, hay #define izquierda, sólo el código que se expandió en.