C and C++ macro definition of variable parameters detailed analysis

  • 2020-04-02 01:33:07
  • OfStack

As you write your code, you often output debugging information to the screen, usually by calling functions like printf.
But when the debugging is done, we need to manually remove or comment out these places.
Recently, I was reading the book "Linux C programming one-stop learning", and I came up with a method:


void myprintf(char* fmt, ...)
{
}
#ifdef DEBUG
#define printf(fmt, args...) myprintf(fmt, ##args)
#endif

In the DEBUG phase, you can turn printf into an empty function by going live with DEBUG.
One potential risk with this is that the glib function will be written silently and the printf output error log will be cancelled.
Thankfully, most glib calls should be fprintf.

Although the problem has been solved, I am very concerned about args... And ##args is still a bit of a mystery. Some information of GCC manual was found online as follows:
Macros with a Variable Number of Arguments
In the 1999 version of ISO C, macros can be defined as functions with variable parameters. The syntax for macros is similar to that for functions.
Here's an example:

#define debug(format, ...) fprintf (stderr, format, __VA_ARGS__)

Here, '... 'is a variable parameter. When this type of macro is called, it (in this case, '... ') is represented as zero or more symbols, including the comma inside, until the end of the right bracket. When called, the symbol sequence set replaces the s/s identifier with s/s in the macro body. More information can be found in the CPP manual.

GCC always supports complex macros, which use a different syntax so that you can give mutable arguments a name, just like any other argument. Here's an example:

#define debug(format, args...) fprintf (stderr, format, args)

This is exactly the same as the ISO c-defined macro example above, but it is more readable and easier to describe.
GNU CPP also has two more complex macro extensions that support the definition formats for the above two formats.
In standard C, you can't omit mutable arguments, but you can pass it an empty argument. For example, the following macro call is illegal in ISO C because there is no comma after the string:

debug ("A message")

GNU CPP allows you to completely ignore variables in this case. In the above example, the compiler will still have a problem (complain) because when the macro is expanded, there is an extra comma after the string inside.
To solve this problem, CPP USES a special '##' operation.
The writing format is:

#define debug(format, ...) fprintf (stderr, format, ## __VA_ARGS__)

Here, the '##' operation causes the preprocessor to remove the comma before the variable if it is ignored or null. If you do provide some variables when a macro is called, GNU CPP will work fine, too, and it will put them after the comma. Like other pasted macro parameters, these parameters are not macro expansion.

Refer to the specific "Linux C programming one-stop learning", by the way, praise this book, written very well!


Related articles: