如何将C宏的某些参数定义为另一个宏?

时间:2019-09-13 13:52:31

标签: c c-preprocessor preprocessor

考虑宏

#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宏来自第三方库,我不希望接触它,并且可能会破坏其他人的代码。当然,实现我自己的版本是一种选择。

3 个答案:

答案 0 :(得分:3)

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

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

宏调用必须具有正确数量的参数。内部宏调用之所以有效,是因为在重新扫描正文之前先扩展了参数。

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

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

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

答案 1 :(得分:1)

尝试这样定义:

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

DEGUB_HOST_IP4仅在第二部分中被替换。因此,当您将其作为参数传递时,它仅被替换为a,而b,c,d被忽略了

答案 2 :(得分:1)

如果您不能更改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 );

你应该很好。