如何在现有变量参数列表中添加新参数?

dro*_*rox 16 c multithreading variadic-functions

在一个多线程程序中,我正在编写一个自定义打印函数,它接受一个可变参数列表.

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

在这个函数里面,我想将当前线程id(使用pthread_self())添加到要打印的消息中.我该怎么做?有没有办法将其添加到现有的va_list?

Arn*_*anc 21

使用可变参数宏:

使用可变参数宏,您可以使用前置或附加的参数调用该函数:

#define t_printf(format, args...) \
    _t_printf(format, thread_id, __VA_ARGS__);
Run Code Online (Sandbox Code Playgroud)

这预先thread_id在其他论点之前.(注意,在_t_printf()函数上你也必须修改格式字符串.)

如果你这样做:

t_printf("some format string", a, b, c);
Run Code Online (Sandbox Code Playgroud)

这将扩展这样做:

_t_printf("some format string", thread_id, a, b, c);
Run Code Online (Sandbox Code Playgroud)

如果t_printf()在没有格式化的其他参数的情况下调用,则会有一个尾随逗号.GCC有一个##扩展,负责根据需要添加逗号:

#define t_printf(format, args...) \
    _t_printf(format, thread_id ##__VA_ARGS__);
Run Code Online (Sandbox Code Playgroud)

完整的宏解决方案:

#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);
    }
}
Run Code Online (Sandbox Code Playgroud)

不修改参数

另一个解决方案是做两个printf()s:

vsnprintf(buffer, bufsize, str, ap);
vfprintf(file_ptr, "[thread_id: %x] %s", thread_id, buffer);
Run Code Online (Sandbox Code Playgroud)

完整解决方案

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);
    }
}
Run Code Online (Sandbox Code Playgroud)


ams*_*mso 5

我相信没有标准的方法来操纵va_list.stdarg.h头定义了用于声明,初始化,复制,终止列表和获取参数的宏(识别类型取决于调用者).

以下是完成相同结果的替代方案的建议:请注意,这会对字符串的格式施加限制.根据您的需要,它可能不是问题:

#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);
    }
}
Run Code Online (Sandbox Code Playgroud)