Получение значения выражений времени компиляции в C
Есть ли способ, чтобы компилятор C (XC16 в моем случае, который основан на gcc) дампировал результаты выражения времени компиляции?
У нас есть много #define, таких как
#define FOO 37.6
#define FOO_BASE 0.035
#define FOO_FIXEDPOINT (int16_t)(FOO/FOO_BASE)
и я хотел бы знать фактические числа, которые компилятор уменьшает эти выражения до.
Обратите внимание, что это НЕ то же самое, что вы хотите знать, что выводит препроцессор; препроцессор не вычисляет математику, она только заменяет вещи. Если я посмотрю на вывод препроцессора, я получаю (эффективно)
#define FOO_FIXEDPOINT (int16_t)(37.6/0.035)
и это компилятор, а не препроцессор, который вычисляет значение.
Еще один важный момент: у меня есть свобода создавать специальный файл .c, который делает такие вещи, как
#include "foo.h"
const int16_t foo_fixedpoint = FOO_FIXEDPOINT;
чтобы я предоставлял место компилятору для выполнения его работы и ставил результаты как константу.
Как полный самодостаточный пример, если я поместил его в foo.c и запустил 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;
}
Я получаю этот вывод:
[... typedefs elided ...]
int main()
{
int x = (int16_t)(37.6/0.035);
}
Ответы
Ответ 1
Посмотрите флаги -fdump-tree-*
на странице параметры отладки, чтобы увидеть выход промежуточного языка (немного низкоуровневый, но вполне читаемый).
Вы можете использовать -fdump-tree-all
для просмотра файла на разных этапах, но, вероятно, все, что вам нужно, это -fdump-tree-original
. Посмотрите вниз в сгенерированном файле *.original
, чтобы найти свою основную функцию:
...
;; Function main (null)
;; enabled by -tree-original
{
int x = 1074;
int x = 1074;
}
Ответ 2
Как обсуждалось в комментариях, особенно если числовые макросы не смешиваются с макросами, имеющими нецифровые типы, просто создать программу, которая печатает свои значения.
Несмотря на то, что ваша среда является кросс-компилятором, это полезное упражнение, потому что все gccs обрабатывают константные выражения внутри одного и того же кода. Это делает математику с расширенной точностью, так что скомпилированные константы находятся в пределах одного ULP точного значения.
Итак, любой gcc должен дать довольно точное представление о том, что происходит в вашем коде.
В 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";
Теперь попробуйте, запустив math.h
.
perl /usr/include/math.h > math_h_syms.c
Это дает:
#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;
}
Компиляция и запуск:
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
Ответ 3
EDIT Это не работает: - (
Даже с трюком для преобразования целого в строку, скомпилированное значение не оценивается препроцессором.
#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))
вывод компилятора (VS2008):
1>A=1
1>B=2
1>C=1+2
Поэтому препроцессор здесь не поможет.
Оригинальный ОТВЕТ
В крайнем случае, если невозможно получить значения из промежуточных файлов, с помощью gcc-опций и т.д.
Я бы grep исходные файлы для #define, перенаправить вывод в новый .c файл и заменить #define на #pragma message
. Вызов gcc в этом файле будет содержать список всех определений. При условии, что ваш компилятор поддерживает #pragma message
.