预编译器函数在编译时在C中进行评估

时间:2010-09-24 21:49:26

标签: c c-preprocessor

我想编写评估的预处理器函数/数组 编译时间。例如,如果我定义

#define MYARR[] {5,4,3,2,1,0}

然后,代码

int x = R[0];

应显示为

int x = 5;

到编译器。 (当然只能在索引中使用文字)。 如果代码大小/内存很关键并且我们不想这样做,那么这很重要 存储MYARR,但我们需要它以方便编码。

编译时间函数也会很好。例如,像

#define MYMAP(n)
#if n==1
5
#else
2

所以,声明

int x = MYMAP(4);

应该以

的形式呈现给编译器
int x = 2;

显然,我们必须使用文字作为参数。这可能吗?

5 个答案:

答案 0 :(得分:5)

当然可能。虽然您可以手动执行此操作,但Boost.Preprocessor已经为您提供了所需的工具:

#include <boost/preprocessor.hpp>
#define SEQ (5)(4)(3)(2)(1)(0)
int x = BOOST_PP_SEQ_ELEM(0, SEQ);

...转变为:

int x = 5;

它还包括算术,比较和控制结构,如IFFORFOR_EACH,枚举,......您只需要记住您可以使用的数据类型与相当有限。

再次使用Boost.PP,你的第二个例子可以这样完成:

#define MYMAP(x) BOOST_PP_IF(BOOST_PP_EQUAL(x, 1), 5, 2)

你当然可以手动实现Boost.PP所做的事情,但考虑到这需要时间和精力,我个人不会打扰。

作为C用户,您不会对Boost的其余部分感兴趣,因此您可能希望使用bcp来提取预处理器组件。

答案 1 :(得分:2)

标准C预处理器无法满足您的需求。为了可靠地获得这种行为,您将需要一个更强大的非标准预处理工具。但是,我不太熟悉可以指导您选择哪一个。

虽然在第二种情况下,您仍然可以在大多数现代编译器上获得所需的效果。例如:

#define MYMAP(n) (((n) == 1) ? 5 : 2)

int x = MYMAP(4);

仍将呈现给编译器

int x = ((4 == 1) ? 5 : 2);

但是编译器本身,如果它是一个合理的现代编译器并允许它进行优化,可能会注意到这个表达式可以在编译时进行评估,并且会发出与

相同的代码。
int x = 2;

但是,保证没有任何东西可以让编译器执行此优化。

答案 2 :(得分:2)

在C99(你真的需要,C89不会这样做)你可以做类似

的事情
#define MyMap(N) (((int const[]){ 3, 4, 5, 6, 7})[N])

如果你的类型是int,但任何其他类型都可以。奇怪的事情(int const[]){ 3, 4, 5, 6, 7}被称为复合文字。基类型的const告诉编译器它不会被修改,并且他可以将具有相同内容的所有事件别名化为同一个固定位置。

编辑,在caf的评论之后: 通常,对于这种方法,大多数编译器都能够完全优化对数组的任何引用,前提是N是一个可以在编译时计算的表达式,例如固定值7或{{ 1}}左右。

如果不是这种情况,编译器必须在某处创建数组对象。使用'a',他可以只生成一个副本,无论您在代码中调用宏的频率如何。当他设法这样做时,数组的初始化将在编译时完成,因此不会有编译时间开销。

我检查了我在机器上的三个编译器:

  • constgcc分配数组 堆栈和每个单独的 调用clang错误,因为开销与数组的大小成正比。
  • MyMap静态分配数组 但为每个电话创建一个新副本 到opencc更好,但还不理想。

答案 3 :(得分:0)

myarr for chars我能做到

#define MYARR(x) ("1234567"[x])
还在思考一下。 Mymap是

#define MYMAP(n) (n == 1 ? 5 : 2)

答案 4 :(得分:0)

没有标准的预处理器命令可以按您希望的方式处理数组。我建议你使用const。

static const int R[] = {5,4,3,2,1,0};
...
int a = R[0];

然后是MYMAP问题......

#define MYMAP(n) ((n)==1?5:2)
...
int a = MYMAP(1); // equals 5.