Estoy leyendo sobre la expansión macro CPP y quería entender la expansión cuando no se proporciona la cadena de token (opcional). Encontré que gcc v4.8.4 hace esto:
$ cat zz.c #define B (B) |B| $ gcc -E zz.c # 1 "zz.c" # 1 "<built-in>" # 1 "<command-line>" # 1 "zz.c" () | |¿Alguien puede explicar por qué la expansión es cero espacios en un caso y uno en el otro?
El preprocesador C opera con "tokens" y cada vez que existe la posibilidad de cambiar el significado o la ambigüedad, siempre agrega espacios en blanco para preservar el significado.
Considere su ejemplo,
(B) no hay ambigüedad o significado que altere si hay un espacio entre ( y ) agregado o no, independientemente del valor macro de B .
Pero no es el caso de
|B| Dependiendo de la macro B , esto de arriba podría ser || o |something| . Entonces, el preprocesador se ve obligado a agregar un espacio en blanco para mantener las reglas léxicas de C.
El mismo comportamiento se puede ver con cualquier otra ficha que pueda alterar el significado. Por ejemplo,
#define B + B+produciría
+ +Opuesto a
++por dicho motivo.
Sin embargo, este es solo el preprocesador que cumple con las reglas léxicas de C. GCC tiene y admite un preprocesador antiguo llamado procesador tradicional que no agregaría espacios en blanco adicionales. Por ejemplo, si llama al preprocesador en modo tradicional :
gcc -E -traditional-cpp file.centonces
#define B (B) |B|producir (sin el espacio en blanco)
() ||La salida de gcc -E intencionalmente no coincide con las reglas exactas especificadas por el estándar C. El estándar C no describe ninguna forma en particular en la que el resultado del preprocesador deba ser visible, y ni siquiera requiere que exista tal forma.
La única vez que se requiere que algún tipo de salida del preprocesador sea visible es cuando se usa el operador # . Y si usa esto, puede ver que no hay espacio.
La respuesta de flaming.toaster señala correctamente que la razón por la que la salida gcc -E inserta un espacio es para evitar que los dos | s de ser analizados como un solo || simbólico. Se requiere el siguiente programa para dar un diagnóstico del error de sintaxis:
#define EMPTY int main() { return 0 |EMPTY| 0; }y el espacio está ahí para asegurarse de que el compilador aún tenga suficiente información para generar el error.
editar: vea la respuesta de hvd sobre la implementación del preprocesador de gcc
Esto puede ser para diferenciar entre los operadores OR lógicos y bit a bit.
Esta muestra:
if (x | 4) printf("true\n"); // Bitwise OR, may or may not be trueEs diferente de:
if (x || 4) printf("true\n"); // Always trueDado que son operadores diferentes con funciones diferentes, es necesario que el preprocesador agregue espacios en blanco para evitar cambiar el significado previsto de la declaración.