【问题标题】:How can I make a C macro for defining function typedefs?如何制作用于定义函数 typedef 的 C 宏?
【发布时间】:2020-03-22 09:33:53
【问题描述】:

我想拿这个:

typedef int (*PTR_FUN)(int);
typedef int (*PTR_FUN_FUN)(PTR_FUN, PTR_FUN);

并像这样定义它:

MAKE_FUNCTION_TYPE(PTR_FUN, int, int);
MAKE_FUNCTION_TYPE(PTR_FUN_FUN, PTR_FUN, PTR_FUN, int);

...其中参数的数量是动态的,最后一个参数是返回类型。

如果不能将最后一个 arg 作为返回类型,则作为第二个 arg。

【问题讨论】:

    标签: c function pointers macros typedef


    【解决方案1】:

    你想要的是一个可变参数宏,它可以接受任意数量的参数。语法为#define MACRO(fixedarg1, fixedarg2, ...)。在宏的主体中,您只需使用__VA_ARGS__ 来引用所有变量参数。

    不幸的是,您不能将最后一个 arg 设为返回类型,因为您必须统一处理整个变量参数块,并且它们必须排在最后。但是,您可以很容易地将第二个 arg 设为返回类型:

    #define MAKE_FUNCTION_TYPE(name, ret, ...) typedef ret (*name)(__VA_ARGS__)
    
    MAKE_FUNCTION_TYPE(v_i, int);
    MAKE_FUNCTION_TYPE(i_v, void, int);
    MAKE_FUNCTION_TYPE(ii_cp, char *, int, int);
    

    这相当于

    typedef int (*v_i)();
    typedef void (*i_v)(int);
    typedef char * (*ii_cp)(int, int);
    

    您可以使用cc -E 进行检查。

    【讨论】:

    • 技术上... 不能匹配零宏参数,所以MAKE_FUNCTION_TYPE(v_i, int) 正式无效。但是大多数编译器无论如何都允许它。 C++20 将使其合法,但我不知道 C 有类似的计划。
    • 尽管在 C 中,int (*)() 无论如何都不是你想要的类型。你想要int (*)(void)
    • @aschepler,C23 很可能采用 __VA_OPT__,这将提供解决此问题的方法
    【解决方案2】:

    如果你真的想要最后的返回类型,那很复杂,但Boost.Preprocessor(适用于 C 和 C++)可以帮助做到这一点:

    #include <boost/preprocessor/tuple.hpp>
    #include <boost/preprocessor/variadic.hpp>
    #include <boost/preprocessor/control/if.hpp>
    #include <boost/preprocessor/comparison/greater.hpp>
    
    #define PP_VARIADIC_BACK(...) \
      BOOST_PP_TUPLE_ELEM(BOOST_PP_DEC(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__)), \
        BOOST_PP_VARIADIC_TO_TUPLE(__VA_ARGS__))
    #define PP_VARIADIC_POP_BACK(...) \
      BOOST_PP_IF(BOOST_PP_GREATER(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__), 1), \
        BOOST_PP_TUPLE_POP_BACK(BOOST_PP_VARIADIC_TO_TUPLE(__VA_ARGS__)), \
        (void))
    
    #define MAKE_FUNCTION_TYPE(name, ...) \
      typedef PP_VARIADIC_BACK(__VA_ARGS__) (*name) PP_VARIADIC_POP_BACK(__VA_ARGS__)
    

    辅助宏PP_VARIADIC_BACK 至少需要一个参数,并导致最后一个参数。辅助宏 PP_VARIADIC_POP_BACK 至少需要一个参数。当它得到多个参数时,它会产生一个括号,其中包含一个逗号分隔的所有参数列表,除了最后一个参数。当它只得到一个参数时,它会产生文本(void)

    然后这些可以与typedef(*name) 部分放在一起。最后的分号被省略了,因为您的示例使用在宏之后提供了一个分号。

    Example preprocessor output on coliru.

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多