que preprocesamiento preprocesador lenguaje informatica ifdef funcion ejemplos directivas directiva define c++ c macros c-preprocessor

preprocesamiento - ¿Por qué esta macro C o C++ no está expandida por el preprocesador?



funcion preprocesador en c++ (4)

Cuando escribe 1e-X todos juntos así, la X no es un símbolo separado para el preprocesador para reemplazar; es necesario que haya espacios en blanco (u otros símbolos) en cada lado. Piénsalo un poco y te darás cuenta de por qué ... :)

Editar: "12-X" es válido porque se analiza como "12", "-", "X", que son tres tokens separados. "1e-X" no se puede dividir así porque "1e-" no forma un token válido por sí mismo, como mencionó Jonathan en su respuesta.

En cuanto a la solución a su problema, puede usar la concatenación de tokens:

#define E(X) 1e-##X int main() { double a = E(10); // expands to 1e-10 return 0; }

¿Alguien puede señalar el problema en el código cuando se compila con gcc 4.1.0?

#define X 10 int main() { double a = 1e-X; return 0; }

Recibo un error: el exponente no tiene dígitos.

Cuando reemplazo X por 10, funciona bien. También comprobé con el comando g ++ -E para ver el archivo con preprocesadores aplicados, no reemplazó X con 10. Tenía la impresión de que el preprocesador reemplaza cada macro definida en el archivo por el texto de reemplazo con la aplicación de cualquier inteligencia. ¿Me equivoco?

Sé que esta es una pregunta muy tonta, pero estoy confundido y prefiero ser tonto que confundido :).

¿Algún comentario / sugerencia?


El preprocesador no es un procesador de texto, funciona en el nivel de tokens. En su código, después de la definición, cada ocurrencia del token X sería reemplazada por el token 10 . Sin embargo, no hay token X en el resto de tu código.

1e-X es sintácticamente inválido y no puede convertirse en un token, que es básicamente lo que el error te está diciendo (dice que para que sea un token válido, en este caso un literal de punto flotante, debes proporcionar un válido exponente).


GCC 4.5.0 tampoco cambia la X.

La respuesta dependerá de cómo el preprocesador interprete las fichas de preprocesamiento y de la regla de "consumo máximo". La regla de ''consumo máximo'' es lo que dicta que ''x +++++ y'' se trata como ''x ++ ++ + y'' y por lo tanto es erróneo, en lugar de ''x ++ + ++ y'' que es legítimo.

El problema es por qué el preprocesador interpreta ''1e-X'' como un token de preprocesamiento único. Claramente, tratará ''1e-10'' como un solo token. No hay una interpretación válida para ''1e-'' a menos que sea seguida por un dígito una vez que pasa el preprocesador. Entonces, tengo que adivinar que el preprocesador ve ''1e-X'' como un solo token (realmente erróneo). Pero no he analizado las cláusulas correctas en el estándar para ver dónde se requiere . Pero la definición de un ''número de preprocesamiento'' o ''número de pp'' en el estándar (ver abajo) es algo diferente de la definición de un entero válido o una constante de coma flotante y permite muchos ''números de pp'' que no son válidos como un entero o constante de coma flotante.

Si ayuda, la salida del compilador Sun C para ''cc -E -v soq.c'' es:

# 1 "soq.c" # 2 int main() { "soq.c", line 4: invalid input token: 1e-X double a = 1e-X ; return 0; } #ident "acomp: Sun C 5.9 SunOS_sparc Patch 124867-09 2008/11/25" cc: acomp failed for soq.c

Por lo tanto, al menos un compilador de C rechaza el código en el preprocesador, es posible que el preprocesador de GCC esté un poco flojo (intenté provocarlo para quejarse con gcc -Wall -pedantic -std=c89 -Wextra -E soq.c pero no emitió un chillido). Y al usar 3 X''s tanto en la macro como en la notación ''1e-XXX'', se demostró que las tres X''s fueron consumidas tanto por GCC como por Sun C Compiler.

C Definición estándar del número de preprocesamiento

Del estándar C - ISO / IEC 9899: 1999 §6.4.8 Números de preprocesamiento:

pp-number: digit . digit pp-number digit pp-number identifier-nondigit pp-number e sign pp-number E sign pp-number p sign pp-number P sign pp-number .

Dado esto, ''1e-X'' es un ''número-pp'' válido, y por lo tanto la X no es un token separado (ni el ''XXX'' en ''1e-XXX'' es un token separado). Por lo tanto, el preprocesador no puede expandir la X; no es un tema simbólico separado para la expansión.


Varias personas han dicho que 1e-X está lexed como un solo token, lo cual es parcialmente correcto. Para explicar:

Hay dos clases de tokens durante la traducción: preprocesamiento de tokens y tokens . Un archivo fuente se descompone inicialmente en tokens de preprocesamiento; estos tokens se usan luego en todas las tareas de preprocesamiento, incluida la macroreproducción. Después del preprocesamiento, cada token de preprocesamiento se convierte en un token; estos tokens resultantes se usan durante la compilación real.

Hay menos tipos de tokens de preprocesamiento que tipos de tokens. Por ejemplo, las palabras clave (por ejemplo, for , while , if ) no son significativas durante las fases de preprocesamiento, por lo que no hay token de preprocesamiento de palabras clave. Las palabras clave son simplemente lexed como identificadores. Cuando tiene lugar la conversión de tokens de preprocesamiento a tokens, se inspecciona cada token de preprocesamiento de identificador; si coincide con una palabra clave, se convierte en un token de palabra clave; de lo contrario, se convierte en un token identificador.

Solo hay un tipo de token numérico durante el preprocesamiento: número de preprocesamiento . Este tipo de token de preprocesamiento corresponde a dos tipos diferentes de tokens: literal entero y literal flotante .

El token de preprocesamiento de número de preprocesamiento se define de manera muy amplia. Efectivamente, coincide con cualquier secuencia de caracteres que comienza con un dígito o un punto decimal seguido de cualquier cantidad de dígitos, no dígitos (por ejemplo, letras), y e+ y e- . Por lo tanto, todos los siguientes son tokens de preprocesamiento de números de preprocesamiento válidos:

1.0e-10 .78 42 1e-X 1helloworld

Los dos primeros se pueden convertir en literales flotantes; el tercero se puede convertir en un literal entero. Los dos últimos no son literales enteros válidos ni literales flotantes; esos tokens de preprocesamiento no se pueden convertir en tokens. Es por esto que puede preprocesar el origen sin error pero no puede compilarlo: el error ocurre en la conversión de tokens de preprocesamiento a tokens.