【问题标题】:How to index a sequence of macros如何索引宏序列
【发布时间】:2021-11-17 14:52:51
【问题描述】:

假设我定义了以下宏:

#define TEST0  100
#define TEST1  101
...
#define TEST9  109

假设我有一个 int 表示这样一个宏的索引:

int idx=3;

如果 idx 等于 3,有没有办法访问 TEST3?

这段代码可以正常工作,因为我在这里传递了一个编译时已知的值:

#define TEST(id) (TEST##id)
printf("Retrieved value: %d\n",TEST(3));

但我还没有找到一种方法来对变量做同样的事情,即:

printf("Retrieved value: %d\n",TEST(i));

添加间接级别

#define STR_INDIR(x) #x
#define STR(x) STR_INDIR(x)

这里也没有帮助,因为此评估发生在编译时。

一种可能性是使用 switch 语句创建一个 C 函数:

int test(int x) {
    switch(x) {
        case 0: return TEST0;break;
        case 1: return TEST1;break;
...
        case 9: return TEST9;break;
    }
}

但这并不能很好地扩展......

【问题讨论】:

  • #define TEST(id) (100+(id)) 怎么样?
  • 您已经注意到为什么这是不可能的:宏名称只存在于预处理器中,在运行时不存在。在几乎所有你认为你想要一个编号的变量序列的情况下,能够通过数字访问它们,那么你想要的通常是一个数组:const int test[] = { [0] = 100, [1] = 101, ... };
  • 这里最好的可能是根本不使用宏。
  • 如果你使用 GCC,那么它有一个语言的扩展,带有一个特殊的 __COUNTER__ 宏,它被增加以在单个翻译单元中非常有用。请参阅the GCC online documentation 了解更多信息。
  • 关于不使用宏或将 TEST(id) 重新定义为 100+(id) 的建议,问题是我不控制定义这些宏的文件,并且它们的值并非微不足道作为一个简单的增量 100,这只是一个例子。

标签: c macros


【解决方案1】:

TEST 可以扩展为级联条件表达式 (?:)。

#define TEST(v)       \
  ((v) == 0 ? TEST0 : \
   (v) == 1 ? TEST1 : \
   (v) == 2 ? TEST2 : \
   -1)

例如int j = TEST(i); 扩展为

int j = ((i) == 0 ? 100 : (i) == 1 ? 101 : (i) == 2 ? 102 : -1);

该解决方案适用于变量i 以及任何整数表达式。如果可能,编译器应该能够优化代码以避免不必要的比较。 但是,可能会多次计算副作用,所以要小心。

此外,如果参数是一个常量表达式,那么结果也是一个常量表达式。这对于函数来说是不可能的,尽管即将推出的 C23 标准会将 constexpr 添加到语言中。

【讨论】:

  • 感谢您的建议。这类似于我在 C test(x) 函数中的 switch 语句,我希望它不会在每次调用该 TEST(v) 宏时显着增加我的代码大小。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-13
  • 1970-01-01
  • 2011-05-14
相关资源
最近更新 更多