Как добавить новый аргумент в существующий список аргументов переменных?
в многопоточной программе я пишу пользовательскую функцию печати, которая принимает список аргументов переменной.
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);
}
}
внутри этой функции я хочу добавить текущий идентификатор потока (через pthread_self()
) для распечатки сообщения. Как я могу это сделать? Есть ли способ добавить его в существующий va_list?
4 ответов
С переменным макросом:
С вариативным макрос можно вызвать функцию с аргументом добавляться:
#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);
}
}
Я считаю, что нет стандартного способа манипулировать 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);
}
}
сохранить его простым. Передайте измененную строку формата в 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);
}
}
во-первых, я не думаю, что есть способ, чтобы распечатать значение pthread_self
(ref: существование pthread_equal
), вот я бросаю его в void*
и использование "%p " - изменить, как вы считаете нужным.
так как, к сожалению, вы не можете добавить к va_list
Я обычно делаю что-то вроде этого:
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);
}
}
поскольку вы исключили это в комментариях, я предполагаю, что это должно сохранить функцию general и только выбранные программы печатают идентификатор потока. Я даю вам следующее чудовище:
#define t_printf(format, ...) t_printf("%p: " format, (void*)pthread_self(), __VA_ARGS__)
он работает только в том случае, если строка формата является литералом, и я не рекомендую использовать ее в производственном коде, но это простой "хак", чтобы выполнить работу.