C++ Macros with variable number of arguments

C++ Macros with a variable number of arguments, or even worse sounding “Variadic Macro’s“.

Why would anybody need this? Like C++ is not “hard enough” already, one might exclaim? Well. standard C/C++ is not hard.  But to learn anything properly, good examples are priceless. Here is one good example.

(Working code example)

In C it is extremely important to get into the habit to free() anything that can be freed and to do it all the time. Just free-free-free, as much as you can.

Being “foolishly” involved with standard C too, I  have developed my little function to “free in bulk”.   Now the test code. First here is some heap-allocated data, that requires a lot of free() calls afterwards.

constexpr size_t newlen = 1024;
constexpr size_t ARRSZ = 9;
typedef char  * arr_type[ARRSZ];
arr_type slave = {
    (char*)calloc( newlen, sizeof(char)), /* 0 */
    (char*)calloc( newlen, sizeof(char)),
    (char*)calloc( newlen, sizeof(char)),
    (char*)calloc( newlen, sizeof(char)),
    (char*)calloc( newlen, sizeof(char)),
    (char*)calloc( newlen, sizeof(char)),
    (char*)calloc( newlen, sizeof(char)),
    (char*)calloc( newlen, sizeof(char)),
    (char*)calloc( newlen, sizeof(char)) /* 8 */
};

In C there are no destructors, so you better be sure you have cleaned up after yourself. Good example is code like above, with a mandatory, long and tedious sequence of calls to standard function free() that has to come after it :

// you must call free on everything 
// you have allocated before
free( slave[0] ); free( slave[1] );
free( slave[2] ); free( slave[3] );
free( slave[4] ); free( slave[5] );
free( slave[6] ); free( slave[7] );
free( slave[8] );

This is not very nice. And it is a bit tiresome. So, I have developed a variadic function with a signature like this:

/*
NOTE: must place NULL as the last arg!
      max args is 255
*/
void free_free_set_them_free(void * vp, ...);

And, I have developed a variadic macro with a normal name to use this useful function:

// variadic macro
#define FREE(...) \ 
free_free_set_them_free(__VA_ARGS__)

Syntax is simple. And the predefined __VA_ARGS__ that will become arguments list expanded. Now I can ease (a bit), a burden of repeated free calls:

FREE(
slave[0], slave[1], slave[2],
slave[3], slave[4], slave[5],
slave[6], slave[7], slave[8],
NULL /* do not ever forget this as last argument! */
);

But. Dear CLANG (aka LVVM) in its standard C reincarnation screams at me now:

warning: passing 'const char *' to parameter of type 'void *' discards qualifiers [-Wincompatible-pointer-types-discards-qualifiers]
    free_free_set_them_free(r1,r2,r3, NULL);
                            ^~
note: passing argument to parameter 'vp' here
void free_free_set_them_free(void * vp, ...)

Hmm, casting each argument will be obviously as tedious as typing separate free calls, if not even  more tedious:

FREE(
(void*)slave[0], (void*)slave[1], (void*)slave[2],
(void*)slave[3], (void*)slave[4], (void*)slave[5],
(void*)slave[6], (void*)slave[7], (void*)slave[8],
NULL /* do not ever forget this as last argument! */
);

Not acceptable.  So, I have tweaked my variadic macro:

// variadic macro with casting
// of a *first* argument
#define FREE(...) \ 
free_free_set_them_free((void *)__VA_ARGS__)

This macro now expands into:

// expansion of a FREE variadic macro
// with casting the __VA_ARGS__
free_free_set_them_free(
 (void*)slave[0], slave[1], 
        slave[2], slave[3], 
        slave[4], slave[5], 
        slave[6], slave[7], 
        slave[8], NULL 
);

Just the first argument is cast as requested.  And that pacifies the compiler since the remaining args types are not checked before they are used inside the variadic function.

// using the FREE variadic macro
FREE (
 slave[0], slave[1], 
 slave[2], slave[3], 
 slave[4], slave[5], 
 slave[6], slave[7], 
 slave[8], 
  NULL /* do not ever forget NULL as the last argument! */
);

And (lo and behold) there is no warning and all is dandy.

But what about this annoying little comment we keep on dragging:/* do not ever forget NULL as the last argument! */  ?

Standard C, variadic functions implementation is based on what is available in: <stdarg.h >. There is no mechanism in there to tell us which is the last argument in standard C variadic functions.  We need to have the concept of the “last argument sentinel”.

Fine. I then do the last and final version of my FREE variadic macro, by simply adding the NULL argument in the call:

// cast the first argument to (void *)
// add the NULL as the last argument
#define FREE(...) \
free_free_set_them_free((void *)__VA_ARGS__, NULL)

A function is implemented to stop if the argument is NULL. And this is one very good example why sometimes we need variadic macros and how to use them. The call to FREE looks now pretty normal, and a good replacement for repeated calls to free().

FREE(
slave[0], slave[1], slave[2], slave[3], slave[4], 
slave[5], slave[6], slave[7], slave[8]
);

No casting and no last argument sentinel necessary.

I am sure you can extrapolate this to your use cases, with variadic functions in standard C.

In case anybody wants a implementation of:

void free_free_set_them_free(void * vp, ...);

Please do let us know in the comments below this post.

So little C++ so much good!
So little C++ so much good!