在C中获取编译时表达式的值

时间:2015-06-30 22:12:40

标签: c gcc

有没有办法让C编译器(在我的情况下是XC16,基于gcc)转储编译时表达式的结果?

我们有很多#defines,比如

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

我想知道编译器将这些表达式减少到的实际数字。

请注意, NOT 与想知道预处理器输出的内容相同;预处理器不计算数学,它只能替代事物。如果我查看预处理器输出,我得到(有效)

#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);
}

3 个答案:

答案 0 :(得分:16)

查看debugging options页面中的标记-fdump-tree-*,以查看中间语言的输出(有点低级但非常易读)。

您可以使用-fdump-tree-all在不同阶段查看文件,但可能只需要-fdump-tree-original。在生成的*.original文件中向下查看以查找您的主要功能:

...
;; Function main (null)
;; enabled by -tree-original

{
  int x = 1074;

    int x = 1074;
}

答案 1 :(得分:2)

正如评论中所讨论的,特别是如果数字宏没有与具有非数字类型的宏混合,则生成打印其值的程序很简单。

即使您的环境是交叉编译器,这也是一个有用的练习,因为所有gcc都在内部使用相同的代码处理常量表达式。这会以扩展精度进行数学运算,以便编译常量在精确值的一个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

答案 2 :(得分:1)

编辑这不起作用: - (

即使有将整数转换为字符串的技巧,预处理器也不会评估组合值。

#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-options等获取中间文件中的值。

我会查找#define的源文件,将输出重定向到新的.c文件中,并将#define替换为#pragma message。在此文件上调用gcc将列出所有定义。原因是您的编译器支持#pragma message