C预处理器 - 递归条件计数宏

时间:2016-09-15 18:22:20

标签: c macros c-preprocessor

我正在尝试编写一个宏来计算序列中特定元素的数量。例如。对于序列(A)(B)(A)我想得到A的计数2 现在采用https://stackoverflow.com/a/12540675/2525536的方法,我最终得到了这段代码:

#define CAT(x, ...) CAT1(x, __VA_ARGS__)
#define CAT1(x, ...) CAT2(x, __VA_ARGS__)
#define CAT2(x, ...) x ## __VA_ARGS__

#define EXPAND(...) __VA_ARGS__
#define EAT(...)
#define DEFER(...) __VA_ARGS__ EAT()
#define OBSTRUCT(...) __VA_ARGS__ DEFER(EAT)()

#define SIZE(seq) CAT(SIZE_, SIZE_0 seq)
#define SIZE_0(...) SIZE_1
#define SIZE_1(...) SIZE_2
#define SIZE_2(...) SIZE_3
#define SIZE_3(...) SIZE_4
#define SIZE_SIZE_0 0
#define SIZE_SIZE_1 1
#define SIZE_SIZE_2 2
#define SIZE_SIZE_3 3
#define SIZE_SIZE_4 4

#define GET_FIRST(x) GET_FIRST2(GET_FIRST1 x)
#define GET_FIRST1(x) x, EAT()
#define GET_FIRST2(x) GET_FIRST3(x)
#define GET_FIRST3(x, ...) x

#define POP_FIRST(x) EAT x

#define EVAL(...)  EVAL1(EVAL1(__VA_ARGS__))
#define EVAL1(...) EVAL2(EVAL2(__VA_ARGS__))
#define EVAL2(...) EVAL3(EVAL3(__VA_ARGS__))
#define EVAL3(...) EVAL4(EVAL4(__VA_ARGS__))
#define EVAL4(...) __VA_ARGS__

#define CHECK_N(x, n, ...) n

#define CHECK(...) CHECK_N(__VA_ARGS__, 0,)
#define CHECK_PROBE(x) x, 1, 

#define NOT(x) CHECK(CAT(NOT_, x))
#define NOT_0 ~, 1,

#define COMPL(b) CAT(COMPL_, b)
#define COMPL_0 1
#define COMPL_1 0

#define BOOL(x) COMPL(NOT(x))

#define IIF(c) CAT(IIF_, c)
#define IIF_0(t, ...) __VA_ARGS__
#define IIF_1(t, ...) t

#define IF(c) IIF(BOOL(c))

#define WHEN(c) IF(c)(EXPAND, EAT)

#define INC(x) CAT(INC_, x)
#define INC_0 1
#define INC_1 2
#define INC_2 3
#define INC_3 4
#define INC_4 5

#define DEC(x) CAT(DEC_, x)
#define DEC_0 0
#define DEC_1 0
#define DEC_2 1
#define DEC_3 2
#define DEC_4 3
#define DEC_5 4

#define COUNT_IF(tpl, data, x) COUNT_IF1(0, SIZE(x), 0, tpl, data, x)
#define COUNT_IF1(i, n, count, tpl, data, x) \
    IF(n) ( \
        OBSTRUCT(CAT) ( \
            COUNT_IF3_, \
            tpl(i, data, GET_FIRST(x)) \
        ) ( \
            OBSTRUCT(COUNT_IF2)() \
                (INC(i), DEC(n), count, tpl, data, POP_FIRST(x)) /* call recursive */ \
        ) \
        , count \
    )
#define COUNT_IF2() COUNT_IF1
#define COUNT_IF3_0 EXPAND
#define COUNT_IF3_1 INC

#define A_EQUAL_A(...) 1
#define A_EQUAL_B(...) 0
#define COUNT_A(i, data, x) CAT(A_EQUAL_, x)(i)

EVAL(COUNT_IF(COUNT_A, ~, (A)))
EVAL(COUNT_IF(COUNT_A, ~, (B)))
EVAL(COUNT_IF(COUNT_A, ~, (A)(B)))
EVAL(COUNT_IF(COUNT_A, ~, (B)(A)))
EVAL(COUNT_IF(COUNT_A, ~, (A)(A)))
EVAL(COUNT_IF(COUNT_A, ~, (B)(B)))
EVAL(COUNT_IF(COUNT_A, ~, (A)(B)(A)))

对于前4个示例,这种方法已经很好用,但最终会为其他示例扩展错误的宏名称(其中INC或EXPAND需要多次扩展)。

原因可能是因为宏在 C 中标记为蓝色,这就是https://stackoverflow.com/a/11640759/2525536的原因。 但我无法找到解决方法。
有人有想法吗?

1 个答案:

答案 0 :(得分:1)

由于我已经收到一些关于使用C预处理器执行此任务的评论并不是处理此问题的合适方式我仍然打算采用这种方式,不仅要最大限度地减少代码依赖性,还要充分利用C提供的功能在我的代码中(这里可能不明显)。
有了这个说法,我发现了为什么宏没有正确扩展,也是一种让预处理器正确完成这项任务的方法 问题是宏从外部(第一个元素)到内部(最后一个元素)生成了类似INC(EXPAND(INC(0)))的构造。预处理器试图解决这个问题,同时始终只知道所有值,直到当前级别/元素。这变成了INC(COUNT_IF1(...))之类的东西,例如预处理器开始替换INC 处理此问题的正确方法是使预处理器将宏从内部扩展到外部 稍微简化代码可以提供这个解决方案:

#define CAT(x, ...) CAT1(x, __VA_ARGS__)
#define CAT1(x, ...) CAT2(x, __VA_ARGS__)
#define CAT2(x, ...) x ## __VA_ARGS__

#define EXPAND(...) __VA_ARGS__
#define EAT(...)
#define DEFER(...) __VA_ARGS__ EAT()
#define OBSTRUCT(...) __VA_ARGS__ DEFER(EAT)()

#define SIZE(seq) CAT(SIZE_, SIZE_0 seq)
#define SIZE_0(...) SIZE_1
#define SIZE_1(...) SIZE_2
#define SIZE_2(...) SIZE_3
#define SIZE_3(...) SIZE_4
#define SIZE_SIZE_0 0
#define SIZE_SIZE_1 1
#define SIZE_SIZE_2 2
#define SIZE_SIZE_3 3
#define SIZE_SIZE_4 4

#define GET_FIRST(x) GET_FIRST2(GET_FIRST1 x)
#define GET_FIRST1(x) x, EAT()
#define GET_FIRST2(x) GET_FIRST3(x)
#define GET_FIRST3(x, ...) x

#define POP_FIRST(x) EAT x

#define EVAL(...)  EVAL1(EVAL1(__VA_ARGS__))
#define EVAL1(...) EVAL2(EVAL2(__VA_ARGS__))
#define EVAL2(...) EVAL3(EVAL3(__VA_ARGS__))
#define EVAL3(...) EVAL4(EVAL4(__VA_ARGS__))
#define EVAL4(...) __VA_ARGS__

#define CHECK_N(x, n, ...) n

#define CHECK(...) CHECK_N(__VA_ARGS__, 0,)
#define CHECK_PROBE(x) x, 1, 

#define NOT(x) CHECK(CAT(NOT_, x))
#define NOT_0 ~, 1,

#define COMPL(b) CAT(COMPL_, b)
#define COMPL_0 1
#define COMPL_1 0

#define BOOL(x) COMPL(NOT(x))

#define IIF(c) CAT(IIF_, c)
#define IIF_0(t, ...) __VA_ARGS__
#define IIF_1(t, ...) t

#define IF(c) IIF(BOOL(c))

#define WHEN(c) IF(c)(EXPAND, EAT)

#define INC(x) CAT(INC_, x)
#define INC_0 1
#define INC_1 2
#define INC_2 3
#define INC_3 4
#define INC_4 5

#define DEC(x) CAT(DEC_, x)
#define DEC_0 0
#define DEC_1 0
#define DEC_2 1
#define DEC_3 2
#define DEC_4 3
#define DEC_5 4

#define IS_PAREN(x) CHECK(IS_PARENT1 x)
#define IS_PARENT1(...) CHECK_PROBE(~)

#define IS_COMPARABLE(x) IS_PAREN(CAT(COMPARE_, x)(()))

#define BITAND(lhs, rhs) CAT(CAT(CAT(BITAND_, lhs), _), rhs)
#define BITAND_0_0 0
#define BITAND_0_1 0
#define BITAND_1_0 0
#define BITAND_1_1 1

#define NOT_EQUAL(lhs, rhs) \
    IIF(BITAND(IS_COMPARABLE(lhs), IS_COMPARABLE(rhs)))( \
        NOT_EQUAL_HELPER, \
        1 NULL \
    )(lhs, rhs)
#define NOT_EQUAL_HELPER(lhs, rhs) IS_PAREN( \
        CAT(COMPARE_, lhs)(CAT(COMPARE_, rhs))(()) \
    )

#define EQUAL(lhs, rhs) COMPL(NOT_EQUAL(lhs, rhs))

#define COUNT_IF(match, x) COUNT_IF1(SIZE(x), match, 0, x)
#define COUNT_IF1(n, match, count, x) \
    IF(n) ( \
        OBSTRUCT(COUNT_IF2)()( \
            DEC(n), \
            match, \
            IF(match(GET_FIRST(x)))(INC, EXPAND)(count), POP_FIRST(x) \
        ) /* call recursive */ \
        , count \
    )
#define COUNT_IF2() COUNT_IF1

#define COMPARE_A(x) x
#define EQUAL_A(x) EQUAL(x, A)


EVAL(COUNT_IF(EQUAL_A, (A)))
EVAL(COUNT_IF(EQUAL_A, (B)))
EVAL(COUNT_IF(EQUAL_A, (A)(B)))
EVAL(COUNT_IF(EQUAL_A, (B)(A)))
EVAL(COUNT_IF(EQUAL_A, (A)(A)))
EVAL(COUNT_IF(EQUAL_A, (B)(B)))
EVAL(COUNT_IF(EQUAL_A, (A)(B)(A)(A)))

P.S。:就复杂性和可维护性而言,11行宏仍然看起来很简单。