Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I add a new argument to the existing variable argument list?

In a multi-threaded program I'm writing a custom print function which accepts a variable argument list.

void t_printf(char * str, ...)
{
    if(file_ptr != NULL)
    {
            va_list ap;
            va_start(ap, str);

            vfprintf(file_ptr, str, ap);

            va_end(ap);

            fflush(file_ptr);
    }
}

Inside this function I want to add the current thread id (using pthread_self()) to the message getting printed. How can I do it? Is there a way to add it to the existing va_list?

like image 622
drox Avatar asked Aug 29 '11 10:08

drox


People also ask

How do you pass variable arguments in C++?

Variable number of arguments in C++Define a function with its last parameter as ellipses and the one just before the ellipses is always an int which will represent the number of arguments. Create a va_list type variable in the function definition. This type is defined in stdarg. h header file.

How do you write a function with variable number of arguments in Python?

As you expect it, Python has also its own way of passing variable-length keyword arguments (or named arguments): this is achieved by using the **kwargs symbol. When using **kwargs, all the keywords arguments you pass to the function are packed inside a dictionary.

Can we pass a variable argument list to a function at run-time question?

Explanation: Every actual argument list must be known at compile time. In that sense it is not truly a variable argument list.


2 Answers

With a variadic macro:

With a variadic macro you can call the function with an argument prepended or appended:

#define t_printf(format, args...) \
    _t_printf(format, thread_id, __VA_ARGS__);

This prepends the thread_id before other arguments. (Note that on the _t_printf() function you have to modify the format string too.)

If you do this:

t_printf("some format string", a, b, c);

This will expand do this:

_t_printf("some format string", thread_id, a, b, c);

If t_printf() is called without other argument that format, you will have a trailing comma. GCC has a ## extension that takes care of adding the comma as needed:

#define t_printf(format, args...) \
    _t_printf(format, thread_id ##__VA_ARGS__);

Complete solution with the macro:

#define t_printf(format, args...) \
    _t_printf(format, thread_id, __VA_ARGS__);

void _t_printf(char * str, ...)
{
    if(file_ptr != NULL)
    {
            char format[1024];

            /* safely prefix the format string with [thread_id: %x] */
            snprintf(format, sizeof(format), "%s%s", "[thread_id: %x] ", str);

            va_list ap;
            va_start(ap, str);

            vfprintf(file_ptr, format, ap);

            va_end(ap);

            fflush(file_ptr);
    }
}

Without modifying the arguments

An other solution is to do two printf()s:

vsnprintf(buffer, bufsize, str, ap);
vfprintf(file_ptr, "[thread_id: %x] %s", thread_id, buffer);

Complete solution:

void _t_printf(char * str, ...)
{
    if(file_ptr != NULL)
    {
            char buffer[1024];

            va_list ap;
            va_start(ap, str);

            vsnprintf(buffer, sizeof(buffer), str, ap);
            vfprintf(file_ptr, "[thread_id: %x] %s", thread_id, buffer);

            va_end(ap);

            fflush(file_ptr);
    }
}
like image 63
Arnaud Le Blanc Avatar answered Nov 06 '22 22:11

Arnaud Le Blanc


I believe there's no standard way to manipulate a va_list. The stdarg.h header defines macros to declare, initialize, copy, terminate lists and fetch an argument (discerning type is up to caller).

Here's the suggestion of an alternative to accomplish the same result: Note that this imposes a limitation on the format of the string. Depending on what you want, it may not be a problem:

#define MAXLEN 256
void t_printf(char * str, ...)
{
    if(file_ptr != NULL)
    {
        va_list ap;
        va_start(ap, str);
        char msg[MAXLEN];

        vsnprintf( msg , MAXLEN , str , ap ); /* msg is guaranteed 
                                               * to be NULL terminated
                                               */

        /* Now that we have the message printed into a string,
         * print the message, along with the thread_id into the
         * console
         */
        fprintf( file_ptr, "thread % 6d: %s", pthread_self() , msg );

        va_end(ap);

        fflush(file_ptr);
    }
}
like image 31
amso Avatar answered Nov 06 '22 23:11

amso