【问题标题】:Macro recursive expansion to a sequence对序列的宏递归扩展
【发布时间】:2023-07-18 04:02:01
【问题描述】:

是否可以定义扩展为“x[0], x[1], x[2], ..., x[i]”的 C/C++ 宏“BUILD(a, i)”?喜欢在

#define BUILD(x, 0) x[0]
#define BUILD(x, 1) x[0], x[1]
#define BUILD(x, 2) x[0], x[1], x[2]
...

似乎 BOOST_PP_ENUM_PARAMS 可以完成这项工作。我想我可以只#include boost,但我很想知道它是如何以及为什么起作用的,任何人都可以解释一下吗?

我想调用一个函数 f(int, ...),它接受 N 个 int 参数 x[i], 0 ceil(sizeof(A) / sizeof(B))。所以很遗憾,我不能使用可变参数或模板。

【问题讨论】:

  • 您真正想解决什么问题? IE。这个宏的结果将用于什么?是否可以稍微更改用法以允许使用模板解决方案(可以递归)?
  • 那么为什么不直接传递数组呢?还是向量更好?

标签: c++ c-preprocessor


【解决方案1】:

有可能,但你必须做一些手工工作并且有上限。

#define BUILD0(x) x[0]
#define BUILD1(x) BUILD0(x), x[1]
#define BUILD2(x) BUILD1(x), x[2]
#define BUILD3(x) BUILD2(x), x[3]
#define BUILD(x, i) BUILD##i(x)

请注意,i 应该是整数文字,而不是常量计算值。

顺便说一句,预处理器比通常的更强大,但是使用这种能力是相当棘手的。 Boost 提供了一个库来简化一些事情,包括迭代。见Boost Preprocessor Library。有另外一个库来存放这些东西,但它的名字现在让我忘记了。

编辑:boost 预处理器库使用了类似的技术。使用额外的技巧来解决一些极端情况问题,在更高级别的设施之间共享实现宏,解决编译器错误等......通常会提高复杂性,这在通用库的上下文中是正常的,但有时会妨碍易于理解实施原则。可能最引人注目的技巧是添加一个间接级别,这样如果第二个参数可以是宏,它就会被扩展。 IE。与

#define BUILD_(x, i) BUILD##i(x)
#define BUILD(x, i) BUILD_(x, i)

一个人可以拨打电话

#define FOO 42
BUILD(x, FOO)

这在我暴露的情况下是不可能的。

【讨论】:

  • 谢谢,有趣的是,BUILD1..BUILD3 几乎相同...我不能有类似#define BUILD_(x, j) BUILD_(x, j-1), x[j ]
  • 它不会有停止条件,宏不能递归启动。
  • “它的名字让我无法理解”你是指Chaos PP吗?
【解决方案2】:

不,它不是——宏不能是递归的。还有你发布的宏 不是可变参数,这意味着“具有不同数量的参数”。

【讨论】:

  • 谢谢,我删除了可变参数标签。
【解决方案3】:

好的, 我有同样的问题,我的目标是使用宏打印 N 字节数组的所有值。我假设你有几乎同样的问题。如果是这种情况,这个解决方案应该可以适应未来的类似问题。

#define HEX_ARRAY_AS_STR(array, len) \
    ({ \
        int print_counter = 0; \
        print_buf = calloc(len*3+1, 1); \
        char *tmp_print_buf = print_buf; \
        uint8_t *array_flower = array;  \
        while(print_counter++ < (len)){ \
            sprintf(tmp_print_buf, "%02X ", *(array_flower)++); \
            tmp_print_buf += 3; \
        } \
        print_buf; \
    })

#define eprintf(...) \
    do{ \
        char *print_buf; \
        printf(__VA_ARGS__); \
        if(print_buf) \
            free(print_buf); \
    }while(0)

int 
main(int argc, char *argv[])
{
    uint8_t sample[] = {0,1,2,3,4,5,6,7};
    eprintf("%s\n", HEX_ARRAY_AS_STR(sample, 8));
    return 0; 
}

【讨论】:

  • 不,这不是我想要做的。无论如何,如果你总是将一个数组传递给 HEX_ARRAY_AS_STR 你可以通过使用 sizeof(array)/sizeof(uint8_t) 摆脱第二个参数
最近更新 更多