Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I define some arguments of a C macro as another macro?

Consider the macro

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

I would like to define the arguments a,b,c,d in another macro. So I have done this:

#define DEBUG_HOST_IP4 192, 168, 0, 123

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

The first call to IP4_ADDR compiles succesfully, while the second one fails with

error: macro "IP4_ADDR" requires 5 arguments, but only 2 given
IP4_ADDR(&debug_host, DEBUG_HOST_IP4 );

Is there a way to make DEBUG_HOST_IP4 expand properly, so the IP4_ADDR macro can work as intended?

EDIT: The IP4_ADDR macro comes from a third-party library, which I would rather not touch, and risk breaking somebody else's code. Of course, implementing my own version is an option.

like image 475
Atilla Filiz Avatar asked Sep 13 '19 13:09

Atilla Filiz


People also ask

Can a macro call another macro in C?

Short answer yes. You can nest defines and macros like that - as many levels as you want as long as it isn't recursive.

Can we pass arguments in macro definition?

A parameter can be either a simple string or a quoted string. It can be passed by using the standard method of putting variables into shared and profile pools (use VPUT in dialogs and VGET in initial macros). This method is best suited to parameters passed from one dialog to another, as in an edit macro.

How can we define macro with different values?

The process to redefine a Macro is: Macro must be defined. When, you want to redefine the Macro, first of all, undefined the Macro by using #undef preprocessor directive. And, then define the Macro again by using #define preprocessor directive.

How do you use macros in arguments?

To define a macro that uses arguments, you insert parameters between the pair of parentheses in the macro definition that make the macro function-like. The parameters must be valid C identifiers, separated by commas and optionally whitespace.


2 Answers

In this case, you can make your outer macro a varargs macro:

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

The macro invocation must have the correct number of arguments. The inner macro invocation works because arguments are expanded before the body is rescanned.

The varargs syntax allows you to either supply the four arguments or use a macro which expands to them.

If you don't want to alter the definition of IP_ADDR, you invoke it indirectly through a wrapper macro:

#define CALL(macro, __VA_ARGS__) macro(...)
// ...
CALL(IP4_ADDR, &debug_host, DEBUG_HOST_IP4 );
like image 101
rici Avatar answered Oct 19 '22 01:10

rici


If you can't alter IP4_ADDR, this is still pretty easy; just wrap it:

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

During the translation (which just moves all of the arguments over, whatever they are), any macros will expand. Then just use your wrapped version in the code.

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

And you should be good to go.

like image 39
Charles Ofria Avatar answered Oct 19 '22 00:10

Charles Ofria