C语言 如何使 GCC 在编译时计算函数



我在考虑以下问题:我想使用使用某种查找表的程序对微控制器(假设AVR大型类型)进行编程。

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

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

#include <avr/io.h>
#include <math.h>
#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 的单独文件中?

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

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

常量表达式可以在翻译期间计算,而不是 运行时,因此可以在常量可能的任何地方使用 是。

常量表达式不得包含赋值、递增、 递减、函数调用或逗号运算符,除非它们是 包含在未计算的子表达式中。115)

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

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

您正在尝试的不是 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 预处理器不能直接做到这一点,因为它没有迭代或递归的工具。

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

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

相关内容

  • 没有找到相关文章

最新更新