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



编译器:MPLABX IDE V5.30 操作系统: 视窗 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))。但是当我编译它时,数据和程序大小发生了巨大变化。当我拆卸它时,有大量的说明,而不是简单地直接在那里放一个数字。

然后我遵循了另一个问题答案的建议,并放置了一个 constsquareroot()函数并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()
}

我如何向编译器表达自己,让它理解代码中的某些行在运行时发生时都是恒定的,以便它可以执行算法,而不仅仅是将标记/文本传递给函数体?

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

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

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

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

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

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

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

你可以反过来解决这个问题。 您知道编译器无法处理函数,但所有编译器都可以处理乘法。 由于 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是一个数字,导致柱线是一个浮点数,那么你将不得不同时执行这两个值

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

最新更新