proceso generar ensamblador compilar compilador compilacion como codigo c gcc

compilar - generar codigo ensamblador gcc



obtener el valor de las expresiones de tiempo de compilaciĆ³n en C (3)

¿Hay alguna forma de que el compilador de C (XC16 en mi caso, que se basa en gcc) descargue los resultados de las expresiones de tiempo de compilación?

Tenemos muchos #defines como

#define FOO 37.6 #define FOO_BASE 0.035 #define FOO_FIXEDPOINT (int16_t)(FOO/FOO_BASE)

y me gustaría saber los números reales a los que el compilador reduce estas expresiones.

Tenga en cuenta que esto NO es lo mismo que querer saber qué produce el preprocesador; el preprocesador no calcula las matemáticas, solo sustituye en las cosas. Si miro la salida del preprocesador, obtengo (efectivamente)

#define FOO_FIXEDPOINT (int16_t)(37.6/0.035)

y es el compilador , no el preprocesador, lo que determina un valor.

Otro punto importante aquí: tengo la libertad de crear un archivo .c especial que hace cosas como

#include "foo.h" const int16_t foo_fixedpoint = FOO_FIXEDPOINT;

de modo que estoy proporcionando un lugar para que el compilador haga su trabajo y ponga los resultados como una constante.

Solo como un ejemplo completo e independiente, si pongo esto en foo.c y ejecuto xc16-gcc.exe -E foo.c :

#include <stdint.h> #define FOO 37.6 #define FOO_BASE 0.035 #define FOO_FIXEDPOINT (int16_t)(FOO/FOO_BASE) int main() { int x = FOO_FIXEDPOINT; }

Obtengo esta salida:

[... typedefs elided ...] int main() { int x = (int16_t)(37.6/0.035); }


Como se comentó en los comentarios, especialmente si las macros numéricas no se mezclan con macros que tienen tipos no numéricos, es sencillo producir un programa que imprima sus valores.

Aunque su entorno es un compilador cruzado, este es un ejercicio útil porque todos los gccs procesan expresiones constantes internamente con el mismo código. Esto hace cálculos matemáticos con precisión extendida, de modo que las constantes compiladas están dentro de un ULP del valor exacto.

Así que cualquier gcc debería dar una idea bastante precisa de lo que está pasando en su código.

En Perl:

print "#include<stdio.h>/n"; print "#include /"$ARGV[0]/"/n"; print "#define S(X) #X/n"; print "int main(void) {/n"; open F, $ARGV[0] or die $!; while (<F>) { print " printf(/"%s=%.13g//n/", S($1), (double)$1);/n" if /#define/s+(/w+)/s+/S/; } print " return 0;/n}/n";

Ahora pruébalo ejecutando math.h

perl /usr/include/math.h > math_h_syms.c

Esto produce:

#include<stdio.h> #include "/usr/include/math.h" #define S(X) #X int main(void) { printf("%s=%.13g/n", S(INFINITY), (double)INFINITY); printf("%s=%.13g/n", S(FP_NAN), (double)FP_NAN); printf("%s=%.13g/n", S(FP_INFINITE), (double)FP_INFINITE); printf("%s=%.13g/n", S(FP_ZERO), (double)FP_ZERO); printf("%s=%.13g/n", S(FP_NORMAL), (double)FP_NORMAL); printf("%s=%.13g/n", S(FP_SUBNORMAL), (double)FP_SUBNORMAL); printf("%s=%.13g/n", S(FP_SUPERNORMAL), (double)FP_SUPERNORMAL); printf("%s=%.13g/n", S(FP_ILOGB0), (double)FP_ILOGB0); printf("%s=%.13g/n", S(FP_ILOGBNAN), (double)FP_ILOGBNAN); printf("%s=%.13g/n", S(MATH_ERRNO), (double)MATH_ERRNO); printf("%s=%.13g/n", S(MATH_ERREXCEPT), (double)MATH_ERREXCEPT); printf("%s=%.13g/n", S(math_errhandling), (double)math_errhandling); printf("%s=%.13g/n", S(M_E), (double)M_E); printf("%s=%.13g/n", S(M_LOG2E), (double)M_LOG2E); printf("%s=%.13g/n", S(M_LOG10E), (double)M_LOG10E); printf("%s=%.13g/n", S(M_LN2), (double)M_LN2); printf("%s=%.13g/n", S(M_LN10), (double)M_LN10); printf("%s=%.13g/n", S(M_PI), (double)M_PI); printf("%s=%.13g/n", S(M_PI_2), (double)M_PI_2); printf("%s=%.13g/n", S(M_PI_4), (double)M_PI_4); printf("%s=%.13g/n", S(M_1_PI), (double)M_1_PI); printf("%s=%.13g/n", S(M_2_PI), (double)M_2_PI); printf("%s=%.13g/n", S(M_2_SQRTPI), (double)M_2_SQRTPI); printf("%s=%.13g/n", S(M_SQRT2), (double)M_SQRT2); printf("%s=%.13g/n", S(M_SQRT1_2), (double)M_SQRT1_2); printf("%s=%.13g/n", S(MAXFLOAT), (double)MAXFLOAT); printf("%s=%.13g/n", S(FP_SNAN), (double)FP_SNAN); printf("%s=%.13g/n", S(FP_QNAN), (double)FP_QNAN); printf("%s=%.13g/n", S(HUGE), (double)HUGE); printf("%s=%.13g/n", S(X_TLOSS), (double)X_TLOSS); printf("%s=%.13g/n", S(DOMAIN), (double)DOMAIN); printf("%s=%.13g/n", S(SING), (double)SING); printf("%s=%.13g/n", S(OVERFLOW), (double)OVERFLOW); printf("%s=%.13g/n", S(UNDERFLOW), (double)UNDERFLOW); printf("%s=%.13g/n", S(TLOSS), (double)TLOSS); printf("%s=%.13g/n", S(PLOSS), (double)PLOSS); return 0; }

Compilación y ejecución:

INFINITY=inf FP_NAN=1 FP_INFINITE=2 FP_ZERO=3 FP_NORMAL=4 FP_SUBNORMAL=5 FP_SUPERNORMAL=6 FP_ILOGB0=-2147483648 FP_ILOGBNAN=-2147483648 MATH_ERRNO=1 MATH_ERREXCEPT=2 math_errhandling=2 M_E=2.718281828459 M_LOG2E=1.442695040889 M_LOG10E=0.4342944819033 M_LN2=0.6931471805599 M_LN10=2.302585092994 M_PI=3.14159265359 M_PI_2=1.570796326795 M_PI_4=0.7853981633974 M_1_PI=0.3183098861838 M_2_PI=0.6366197723676 M_2_SQRTPI=1.128379167096 M_SQRT2=1.414213562373 M_SQRT1_2=0.7071067811865 MAXFLOAT=3.402823466385e+38 FP_SNAN=1 FP_QNAN=1 HUGE=3.402823466385e+38 X_TLOSS=1.414847550406e+16 DOMAIN=1 SING=2 OVERFLOW=3 UNDERFLOW=4 TLOSS=5 PLOSS=6


Echa un vistazo a las banderas -fdump-tree-* en la página de opciones de depuración , para ver el resultado del lenguaje intermedio (un poco bajo nivel pero bastante legible).

Puede usar -fdump-tree-all para ver el archivo en diferentes etapas, pero probablemente todo lo que necesita es el -fdump-tree-original . Mire hacia abajo en el archivo *.original para buscar su función principal:

... ;; Function main (null) ;; enabled by -tree-original { int x = 1074; int x = 1074; }


EDIT Esto no funciona :-(

Incluso con el truco para convertir un entero en una cadena, el valor compuesto no es evaluado por el preprocesador.

#define STR_HELPER(x) #x #define STR(x) STR_HELPER(x) #define A 1 #define B 2 #define C A+B #pragma message("A=" STR(A)) #pragma message("B=" STR(B)) #pragma message("C=" STR(C))

Salida del compilador (VS2008):

1>A=1 1>B=2 1>C=1+2

Así que el preprocesador no ayudará aquí.

RESPUESTA original Como último recurso, si no hay forma de obtener los valores de los archivos intermedios, por medio de gcc-options, etc.

Me gustaría grep los archivos de origen para #define, redirigir la salida en un nuevo archivo .c y reemplazar #define por el #pragma message . Llamar a gcc en este archivo listaría todas las definiciones. De causa siempre que su compilador apoyara el #pragma message .