如何让GCC在编译时评估函数?

我正在考虑以下问题:我想用一个使用某种查找表的程序编程一个微控制器(比如一个AVR mega类型)。

第一次尝试是将表定位在一个单独的文件中,并使用任何其他脚本语言/程序/创建它。在这种情况下,为C创建必要的源文件需要付出相当大的努力。

我现在的想法是使用预处理器和编译器来处理事情。 我尝试用一​​个正弦值表来实现它(仅作为示例):

#include  #include  #define S1(i,n) ((uint8_t) sin(M_PI*(i)/n*255)) #define S4(i,n) S1(i,n), S1(i+1,n), S1(i+2,n), S1(i+3,n) uint8_t lut[] = {S4(0,4)}; void main() { uint8_t val, i; for(i=0; i<4; i++) { val = lut[i]; } } 

如果我编译这段代码,我会得到有关sin函数的警告。 在程序集中,在.data部分中没有任何内容。 如果我只是删除第三行中的sin ,我得到程序集中的数据。 显然,所有信息都可以在编译时获得。

你能否告诉我是否有办法实现我的目的:编译器计算尽可能多的离线值? 或者是使用外部脚本/程序/ …来计算表条目并将它们添加到一个单独的文件中的最佳方式,该文件只是#include d?

这里的一般问题是sin调用使得这个初始化事实上是非法的,根据C语言的规则,因为它本身不是常量表达式 ,而是你正在初始化静态存储持续时间的数组,这需要这样做。 这也解释了为什么你的数组不在.data部分。

C11(N1570)§6.6/ 2,3常数表达式(强调我的)

可以在转换期间而不是运行时期间评估常量表达式,并且因此可以在常量可以在任何地方使用。

常量表达式不应包含赋值,递增,递减, 函数调用或逗号运算符,除非它们包含在未评估的子表达式中.15)

然而,正如@ ShafikYaghmour的评论一样,GCC将用其内置对应物替换sin函数调用(除非存在-fno-builtin选项),这可能被视为常量表达式。 根据GCC提供的6.57其他内置function :

GCC包含标准C库中许多function的内置版本。 即使您指定-fno-builtin选项,前缀为__builtin_的版本也始终被视为具有与C库函数相同的含义。

你正在尝试的不是C语言的一部分。 在这种情况下,我按照这种模式编写了代码:

 #if GENERATE_SOURCECODE int main (void) { ... Code that uses printf to write C code to stdout } #else // Source code generated by the code above ... Here I paste in what the code above generated // The rest of the program #endif 

每次需要更改它时,都会运行定义了GENERATE_SOURCECODE的代码,并粘贴输出。 如果您的代码是自包含的,那么生成的输出只有在生成它的代码发生变化时才会发生变化。

首先,不用说你应该评估(可能通过实验)是否值得这样做。 您的查找表将增加您的数据大小和程序员工作量,但可能会或可能不会提供您所需的运行时速度增加。

如果您仍想这样做,我认为C预处理器不能直接执行,因为它没有迭代或递归的function。

最有效的方法是用C或其他语言编写程序来打印表的C源,然后使用预处理器将该文件包含在程序中。 如果您使用的是make类的工具,则可以创建规则来生成表文件,并使.c文件依赖于该文件。

另一方面,如果您确定永远不会更改此表,您可以编写一个程序来生成它一次并将其粘贴。