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

问题描述 投票:0回答:3

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

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

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

#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
将被
10
代替,而不是
(sqrt(foo))
。但当我编译它时,数据和程序大小发生了巨大的变化。当我拆开它时,有大量的说明,而不是简单地直接放一个数字。

然后我按照另一个问题的答案的建议并放置了一个 const

squareroot()
函数和
const int
声明,但编译器给出了类似的警报;

main.c:50:38: error: initializer element is not a compile-time constant

这是第二次尝试;

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

我如何向编译器表达自己的意思,使其理解代码中的某些行在运行时发生的情况下都是不变的,以便它可以进行算术运算,而不是简单地将标记/文本传递给函数体?

c compiler-errors c-preprocessor pic mplab
3个回答
4
投票

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

编译器必须在常量表达式中支持哪些表达式的列表可以在当前 C 标准的第 6.6 节中找到,有关摘要请参阅此处。不包括调用函数。

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

如果您必须使用不支持在常量表达式中调用浮点函数

sqrt
的编译器,那么您的选择包括:

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

3
投票

大多数不错的编译器都会为你做这件事

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,您就没有机会只购买该“产品”。


0
投票

您可以反过来解决问题。 您知道编译器无法处理函数,但所有编译器都可以处理乘法。 由于 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 的值即可。 对于#define,您需要在使用#define 的地方进行修补。 如果 foo 是一个数字,导致 bar 成为浮点数,那么您将必须执行这两个值

const int bar = 9;
const int foo = 90; /* bar * bar */
© www.soinside.com 2019 - 2024. All rights reserved.