在多线程程序中,我正在编写一个自定义打印函数,它接受一个可变参数列表。
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);
}
}
在此函数中,我想将当前线程ID (使用pthread_self()
)添加到要打印的消息中。我该怎么做?有没有办法将它添加到现有的va_list?
答案 0 :(得分:20)
使用可变参数宏,您可以使用前置或附加的参数调用该函数:
#define t_printf(format, args...) \
_t_printf(format, thread_id, __VA_ARGS__);
这在其他参数之前加thread_id
。 (请注意,在_t_printf()
函数上,您还必须修改格式字符串。)
如果你这样做:
t_printf("some format string", a, b, c);
这将扩展这样做:
_t_printf("some format string", thread_id, a, b, c);
如果在没有格式化的其他参数的情况下调用t_printf()
,则会有一个尾随逗号。 GCC有一个##
扩展名,负责根据需要添加逗号:
#define t_printf(format, args...) \
_t_printf(format, thread_id ##__VA_ARGS__);
使用宏完成解决方案:
#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);
}
}
另一个解决方案是做两个printf()s:
vsnprintf(buffer, bufsize, str, ap);
vfprintf(file_ptr, "[thread_id: %x] %s", thread_id, buffer);
完整的解决方案:
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);
}
}
答案 1 :(得分: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);
}
}
答案 2 :(得分:3)
保持简单。将修改后的格式字符串传递给vfprintf:
void t_printf(char * str, ...)
{
if(file_ptr != NULL)
{
char fmt[MAXLEN];
va_list ap;
va_start(ap, str);
// amend format and insert thread id
snprintf(fmt, MAXLEN, "thread id: %d: %s", pthread_self(), str);
vfprintf(file_ptr, fmt, ap);
va_end(ap);
fflush(file_ptr);
}
}
答案 3 :(得分:1)
首先,我认为没有一种支持的方式可以打印pthread_self
的值(参考:pthread_equal
的存在),这里我将它转换为{{1}并使用“%p” - 根据需要进行更改。
很遗憾,您不能添加void*
我通常会这样做:
va_list
由于你在评论中排除了这一点,我认为这是为了保持函数的一般性,并且只选择程序打印线程id。我给你以下怪物:
void t_printf(char * str, ...)
{
if(file_ptr != NULL)
{
va_list ap;
va_start(ap, str);
#if defined(USING_THREADS) && defined(LOGGING)
fprintf(file_ptr, "%p", (void*)pthread_self());
#endif
vfprintf(file_ptr, str, ap);
va_end(ap);
fflush(file_ptr);
}
}
只有格式字符串是文字字符串才有效,我不建议在生产代码中使用它,但是完成工作很容易“破解”。