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

Chr*_*olf 5 c gcc pre-compilation

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

第一次尝试是将表定位在单独的文件中,并使用任何其他脚本语言/程序/创建它.在这种情况下,为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];
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

Grz*_*ski 5

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

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

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

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

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

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