我想编写在以下位置评估的预处理器函数/数组 编译时间。例如,如果我定义
#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;
显然,我们必须使用文字作为参数。这可能吗?
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;
它还包括算术、比较和控制结构,如 IF
、
FOR
、
FOR_EACH
、枚举……您只需记住,您可以使用的数据类型相当有限。再次利用
Boost.PP,你的第二个例子可以像这样完成:
#define MYMAP(x) BOOST_PP_IF(BOOST_PP_EQUAL(x, 1), 5, 2)
你当然可以手动实现Boost.PP所做的事情,但考虑到这需要时间和精力,我个人不会打扰。作为 C 用户,您不会对 Boost 的其余部分感兴趣,因此您可能需要使用
bcp 来提取预处理器组件。
尽管在第二种情况下,您仍然可以在大多数现代编译器上获得您想要的效果。例如:
#define MYMAP(n) (((n) == 1) ? 5 : 2)
int x = MYMAP(4);
仍将
呈现给编译器为:
int x = ((4 == 1) ? 5 : 2);
但是编译器本身,如果它是一个合理的现代编译器并且您允许它优化,则可能会注意到这个表达式可以在编译时求值,并且会发出与
相同的代码
int x = 2;
但是,没有任何东西可以
保证编译器将执行此优化。
#define MyMap(N) (((int const[]){ 3, 4, 5, 6, 7})[N])
只要您的类型是
int
,但任何其他类型都可以。奇怪的东西
(int const[]){ 3, 4, 5, 6, 7}
被称为复合文字。基本类型中的
const
告诉编译器它不会被修改,并且他可以将所有具有相同内容的实例别名到相同的固定位置。
编辑,咖啡馆评论后:
一般来说,对于这种方法,大多数编译器将能够完全优化对数组的任何引用,前提是 N
是可以在编译时计算的表达式,例如固定值
7
或
'a'
等。如果不是这种情况,编译器必须在某处创建数组对象。有了
const
,他就可以只生成它的一份副本,无论您在代码中调用宏的频率如何。当他设法这样做时,数组的初始化将在编译时完成,因此不会有编译时间开销。我检查了我机器上的三个编译器:
gcc
和
clang
分配数组 堆栈和每个单独的这个 调用
MyMap
、bad,因为开销与数组的大小成正比。
opencc
静态分配数组 但为每次调用创建一个新副本 到
MyMap
,更好,但还不够理想。
#define MYARR(x) ("1234567"[x])
仍在思考整数。我的地图是
#define MYMAP(n) (n == 1 ? 5 : 2)
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.