【问题标题】:How can I define some arguments of a C macro as another macro?如何将 C 宏的某些参数定义为另一个宏?
【发布时间】:2020-01-15 09:46:06
【问题描述】:

考虑宏

#define IP4_ADDR(ipaddr, a,b,c,d)  (ipaddr)->addr = PP_HTONL(LWIP_MAKEU32(a,b,c,d))

我想在另一个宏中定义参数 a,b,c,d。所以我这样做了:

#define DEBUG_HOST_IP4 192, 168, 0, 123

IP4_ADDR(&debug_host, 192, 168, 0, 123 );
IP4_ADDR(&debug_host, DEBUG_HOST_IP4 );

对 IP4_ADDR 的第一次调用编译成功,而第二次调用失败

错误:宏“IP4_ADDR”需要 5 个参数,但只给出了 2 个
IP4_ADDR(&debug_host, DEBUG_HOST_IP4);

有没有办法使DEBUG_HOST_IP4 正确扩展,以便IP4_ADDR 宏可以按预期工作?

编辑:IP4_ADDR 宏来自第三方库,我不想碰它,并且冒着破坏别人代码的风险。当然,实现我自己的版本是一种选择。

【问题讨论】:

  • Boost.Preprocessor 有BOOST_PP_EXPAND,你可以检查它的实现。 Boost 是 C++,但是这两种语言的预处理器在很多方面是相似的,这个特定的宏应该是可移植的。
  • 查看this article,尤其是关于扩展和递归的部分。
  • 毫无疑问不受欢迎但最明智的建议是首先摆脱宏。 IP4_ADDR 看起来是一个很好的函数候选者。
  • 您无法更改预处理器扩展宏的方式,因此您的替代方法是更改​​宏或更改宏的每次使用。我在答案中添加了第二个选项。

标签: c c-preprocessor preprocessor


【解决方案1】:

尝试这样定义:

#define IP4_ADDR(ipaddr, HOST)  (ipaddr)->addr = PP_HTONL(LWIP_MAKEU32(HOST))

DEGUB_HOST_IP4 只会在第二部分被替换。所以当你把它作为参数传递时,它只被替换为a,而b、c、d被忽略了

【讨论】:

    【解决方案2】:

    在这种情况下,您可以将外部宏设为可变参数宏:

    #define IP4_ADDR(ipaddr, ...)  (ipaddr)->addr = PP_HTONL(LWIP_MAKEU32(__VA_ARGS__))
    

    宏调用必须有正确数量的参数。内部宏调用有效,因为在重新扫描主体之前扩展了参数。

    可变参数语法允许您提供四个参数或使用扩展为它们的宏。

    如果您不想更改IP_ADDR 的定义,您可以通过包装宏间接调用它:

    #define CALL(macro, __VA_ARGS__) macro(...)
    // ...
    CALL(IP4_ADDR, &debug_host, DEBUG_HOST_IP4 );
    

    【讨论】:

    • 谢谢你的第二部分,我有一个类似的解决方案。测试后我会接受的。
    【解决方案3】:

    如果您不能更改 IP4_ADDR,这仍然很容易;把它包起来:

    #define MY_IP4_ADDR(...) IP4_ADDR(__VA_ARGS__)
    

    在翻译过程中(只是将所有参数移过来,不管它们是什么),任何宏都会展开。然后在代码中使用你的包装版本。

      MY_IP4_ADDR(&debug_host, 192, 168, 0, 123 );
      MY_IP4_ADDR(&debug_host, DEBUG_HOST_IP4 );
    

    你应该很高兴。

    【讨论】:

    • 这正是我最终要做的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多