define - Extensión cpp de macro sin token-string
define c++ (3)
El preprocesador C opera en "tokens" y siempre que haya una posibilidad de cambiar el significado o la ambigüedad, siempre agrega espacios en blanco para preservar el significado.
Considera tu ejemplo,
(B)
no hay ambigüedad ni significado que altere si hay un espacio entre (
y )
agregado o no, independientemente del valor macro de B
Pero no es el caso con
|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 otro token que pueda alterar el significado. Por ejemplo,
#define B +
B+
produciría
+ +
Opuesto a
++
por la mencionada razón.
Sin embargo, este es solo el preprocesador que cumple con las reglas lexicales. GCC tiene y es compatible con un preprocesador antiguo llamado procesador tradicional que no agregaría ningún espacio en blanco adicional. Por ejemplo, si llama al preprocesador en modo tradicional :
gcc -E -traditional-cpp file.c
entonces
#define B
(B)
|B|
producir (sin el espacio en blanco)
()
||
Estoy leyendo sobre la expansión de macros CPP y quería entender la expansión cuando no se proporciona la cadena 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 tiene cero espacios en una instancia y uno en la otra?
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 particular en que el resultado del preprocesador debe ser visible, y ni siquiera lo requiere.
La única vez que se requiere que algún tipo de salida de preprocesador sea visible es cuando se utiliza #
operador #
. Y si usa esto, puede ver que no hay espacio.
La respuesta de flaming.toaster correctamente señala que la razón por la cual la salida gcc -E
inserta un espacio es para evitar que los dos |
s de ser analizado como un single ||
simbólico. El siguiente programa es necesario 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 todavía tenga suficiente información para generar realmente 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 a nivel de bit.
Esta muestra:
if (x | 4) printf("true/n"); // Bitwise OR, may or may not be true
Es diferente de:
if (x || 4) printf("true/n"); // Always true
Debido a que son operadores diferentes con funciones diferentes, es necesario que el preprocesador agregue espacios en blanco para evitar cambiar el significado pretendido de la declaración.