簡體   English   中英

在C中獲取編譯時表達式的值

[英]getting the value of compile-time expressions in C

有沒有辦法讓C編譯器(在我的情況下是XC16,基於gcc)轉儲編譯時表達式的結果?

我們有很多#defines之類的

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

查看調試選項頁面中的標志-fdump-tree-* ,以查看中間語言的輸出(有點低級但非常易讀)。

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

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

{
  int x = 1074;

    int x = 1074;
}

正如在注釋中所討論的那樣,特別是如果數字宏沒有與具有非數字類型的宏混合,則生成打印其值的程序很簡單。

即使您的環境是交叉編譯器,這也是一個有用的練習,因為所有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

編輯這不起作用:-(

即使有將整數轉換為字符串的技巧,預處理器也不會評估組合值。

#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 grep源文件,將輸出重定向到新的.c文件中,並用#pragma message替換#define。 在此文件上調用gcc將列出所有定義。 原因是您的編譯器支持#pragma message

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM