Variadic C/C++

Ξ September 27th, 2009 | → 0 Comments |
Programming |, , |

Did you ever wanted to create your own printf and never knew how to make your functions or methods take a variable number or arguments? Then this test if for you…

If you ever took the chance to read the manual page for printf functions, I may noticed the following definition for the this C standard variadic function (yes, thats’s how functions/methods that a variable number of arguments):

int printf(const char *format, …);

All the magic is done by that ’strange’ three points. Let’s see how one can one them. Imagine you what to implement a logging interface using the following variadic function (note: level_t is an enumerate of the available log levels):

void log(level_t level, const char *format, …);

This allows you to add log entries like:

log(FATAL, “Exiting to unknown problem.”);
log(ERROR, “Unable to open file %s.”, filename);
log(WARNING, “Falling to default configuration.”);
log(INFORMATION, “Computation at step %d : %s.”, step, description);
log(DEBUG, “Running iteration %d.”, i);


After understanding that the ’strange’ three points represent a va_list which contains the list of arguments. The way to access the contents of the three points is as follow:

void log(level_t level, const char *format, …)
{
  va_list args                // 1. create the list of pointers to unnamed arguments
  va_start(args, format);     // 2. initialize the list of pointers to arguments
                              //    note: the second argument must be the last of fixed arguments
 
printf( “Level %d”, level );// 3. use printf to display the required information
  while( !va_end(args) )      // 4. iterate over available arguments, until the end of the list
  {
    const char *str

       = va_arg( args, char * ); // 5. access the argument value
                                              //    note: it is necessary to provide the type of the argument

    printf( “%s\n”, str );       // 6. display the selected argument
  }

  va_end( args )              // 7. cleanup the argument list
}

This is one way to do it, but you can implement the same function based of a printf sibling, called vprintf which allows you to pass the va_list directly to printf. This also solves the problem with the cast required at steo 5. of the previous example. So, this is the resulting implementation:

void log(level_t level, const char *format, …)
{
  va_list args;
  va_start(args, format);
 
printf( “Level %d”, level );
  vprintf( format, args );    // notice the use of vprintf
  va_end( args );
}

There is also the possibility to provide the developer with variadic MACROS. See here for more details.

 

On the nightstand...


    The Art of Agile Development


    Beautiful Architecture


    Modern C++ Design


    Large Scale C++ Software Design

Personal

Friends


Interesting


Shared Readings