在 C 语言中编译时评估的预处理器函数

发布于 2024-09-25 04:30:28 字数 531 浏览 1 评论 0原文

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

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

then,则应将代码

int x = R[0];

呈现给

int x = 5;

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

编译时函数也很好。例如,类似

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

So, 语句

int x = MYMAP(4);

应该呈现给编译器,因为

int x = 2;

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

I want to write preprocessor functions/arrays that are evaluated at
compile time. For example, if I define

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

then, the code

int x = R[0];

should be presented as

int x = 5;

to the compiler. (Of course only literals can be used in the index).
This is important if code size/memory is critical and we don't want to
store MYARR, but we need it for coding convenience.

Compile time functions would also be good. For example, something like

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

So, the statement

int x = MYMAP(4);

should be presented to the compiler as

int x = 2;

Obviously, we have to use a literal as the argument. Is this possible?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

笛声青案梦长安 2024-10-02 04:30:28

当然有可能。虽然您可以手动执行此操作,但 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< /code>、枚举……您只需记住,您可以使用的数据类型相当有限。

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

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

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

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

Sure it’s possible. While you could do that manually, Boost.Preprocessor already gives you the tools you need:

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

... gets transformed to:

int x = 5;

It also includes arithmetic, comparisons and control structures like IF, FOR, FOR_EACH, enumerations, ... You just have to keep in mind that the data types you can work with are rather limited.

Utilizing Boost.PP again, your second example can be done like so:

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

You can of course implement manually what Boost.PP does, but considering the time and effort needed for this I personally wouldn't bother.

As a C user, you won't be interested in the rest of Boost, so you might want to use bcp to extract the preprocessor components.

尐籹人 2024-10-02 04:30:28

标准 C 预处理器不会执行您想要的操作。为了可靠地获得这种行为,您将需要一个更强大的非标准预处理工具。然而,我对可用的内容还不够熟悉,无法引导您找到您可能想要的内容。

尽管如此,在第二种情况下,您仍然可以在大多数现代编译器上获得您想要的效果。例如:

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

int x = MYMAP(4);

仍将呈现给编译器为:

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

但是编译器本身,如果它是一个合理的现代编译器并且您允许它优化,可能会注意到这个表达式可以在编译时计算 -时间并会发出与然而相同的代码

int x = 2;

保证编译器将执行此优化。

The standard C preprocessor will not do what you want. To get this sort of behavior reliably you are going to need a more powerful, nonstandard preprocessing tool. However, I'm not familiar enough with what's available to direct you to which one you might want.

Although, in the second case, you may still be able to get the effect you want on most modern compilers. For example:

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

int x = MYMAP(4);

will still be presented to the compiler as:

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

but the compiler itself, if it is a reasonable modern compiler and you allow it to optimize, will likely notice that this expression can be evaluated at compile-time and will emit code that is identical to

int x = 2;

However, there's nothing that guarantees that a compiler will perform this optimization.

娇妻 2024-10-02 04:30:28

C99 中(你确实需要它;C89 不行)你可以这样做,

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

只要你的类型是 int,但任何其他类型都会做。奇怪的东西 (int const[]){ 3, 4, 5, 6, 7} 被称为复合文字。基本类型的 const 告诉编译器它不会被修改,并且他可以将所有具有相同内容的实例别名到相同的固定位置。

一般来说,对于这种方法,大多数编译器将能够完全优化对数组的任何引用,只要 N 是一个可以在编译时计算的表达式,例如固定值 7'a' 左右。

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

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

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

In C99 (you really need that; C89 wouldn't do) you can do with something like

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

provided your type is int, but any other type would do. The weird thing (int const[]){ 3, 4, 5, 6, 7} is called a compound literal. The const in there for the base type tells the compiler that it will not be modified and that he may alias all occurrences with the same contents to the same fixed location.

Generally, for this approach, most compilers will be able to completely optimize any reference to the array away, provided N is an expression that can be evaluated at compile time, such as a fixed value 7 or 'a' or so.

If this is not the case, the compiler has to create the array object somewhere. With the const he could be allowed to generate just one copy of it, regardless how often you call the macro in your code. When he manages to do so, the initialization of the array would be done at compile time, so there would be no compile time overhead.

I checked this for the three compilers that I have on my machine:

  • gcc and clang allocate the array on
    the stack and this for every single
    call to MyMap, bad, since the overhead is proportional to the size of the array.
  • opencc allocates the array statically
    but creates a new copy for every call
    to MyMap, better, but not yet ideal.
酷到爆炸 2024-10-02 04:30:28

没有标准的预处理器命令可以按照您想要的方式处理数组。我建议你使用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.

There is no standard preprocessor commands that handle arrays the way you are wanting. I suggest that you use a const.

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

Then for the MYMAP question...

#define MYMAP(n) ((n)==1?5:2)
...
int a = MYMAP(1); // equals 5.
满身野味 2024-10-02 04:30:28

myarr 对于字符我仍然可以

#define MYARR(x) ("1234567"[x])

思考整数。我的地图是

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

myarr for chars I can do

#define MYARR(x) ("1234567"[x])

still pondering ints. Mymap is

#define MYMAP(n) (n == 1 ? 5 : 2)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文