强制编译器在预处理期间进行算术计算

Forcing compiler to make arithmetic calculations during preprocess

编译器:MPLABX IDE V5.30 操作系统:Windows10

我想做的是定义一些常量值(使将来的更改更容易)并在预处理期间通过算术运算创建一些其他常量。然后在运行时使用这些常量。

这是我的意图的示例版本;

#include <stdio.h>
#include <math.h>

#define foo 100 //in case you change FOO in circuit, change this too!
#define bar (sqrt(foo))

int main(void) {
    if ( bar > user_input)
    {
    do();
    }
}

问题是,我想,既然输入是一个常量值,定义的东西会被编译器计算出来,bar会被[=代替13=] 而不是 (sqrt(foo))。但是当我编译它时,数据和程序大小发生了巨大变化。当我拆开它时,有大量的指令,而不是简单地直接把一个数字放在那里。

然后我听从了另一个问题的答案的建议,并放置了一个 const squareroot() 函数和 const int 声明,但编译器发出了类似的警告; main.c:50:38: error: initializer element is not a compile-time constant

here is the second try;
#include <stdio.h>
#include <squareroot.h>

#define foo 100 //in case you change FOO in circuit, change this too!
const int bar=squareroot(foo);

int main(void) {
    if ( bar > user_input)
    {
    do();
    }
}

const int squareroot(const int input)
{
do()
}

我如何向我的编译器表达自己的意思,让它理解我的代码中的某些行在运行时无论发生什么都是不变的,这样它就可以进行算术而不是简单地将 token/text 传递给函数体?

大多数体面的编译器都会为你做这件事

https://godbolt.org/z/6f5Awz

#define foo 100 //in case you change FOO in circuit, change this too!
#define bar (sqrt(foo))

volatile int x;

int main(void) {
    x = bar;
}

结果:

x:
        .zero   4
main:
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR x[rip], 10
        mov     eax, 0
        pop     rbp
        ret

唯一的问题是 MPLAB 是否是一个不错的编译器。至少在免费版本中不是。 Microchip 故意使生成的代码更糟,以迫使您做出购买决定。如果您决定使用 PIC uC,您将没有机会只购买该“产品”。

#define 是明文替换,仅此而已。所有 #define 转换都发生在预处理翻译阶段,该阶段在任何表达式分析等之前。

可以在当前 C 标准的第 6.6 节中找到编译器必须在常量表达式中支持的表达式的列表,以获取摘要 see here。不包括调用函数。

(当然,个别编译器可能会提供标准不需要的功能)。

如果您必须使用不支持在常量表达式中调用浮点函数 sqrt 的编译器,那么您的选择包括:

  • 硬编码您的常量,运行另一个预处理阶段以根据需要设置它们。
  • 有一个在 main 函数开始时初始化的全局变量。

你可以反过来解决这个问题。您知道编译器无法处理函数,但所有编译器都可以处理乘法。由于 sqrt(x)*sqrt(x) = x

#define bar (10)
const int foo = bar * bar;

这将为您提供 foo 在任何编译器上的编译时间常量。不幸的是,我不知道如何将 XC8 编译器的输出粘贴到 Web 浏览器,所以我无法向您展示结果。或者,不要打扰#define。

const int bar = 10;
const int foo = bar * bar;

如果您必须修补代码,在调试期间,您只需要修补bar 和foo 的值。使用#defines,您需要在使用#define 的任何地方对其进行修补。如果 foo 是一个导致 bar 成为浮点数的数字,那么您将必须执行两个值

const int bar = 9;
const int foo = 90; /* bar * bar */