2017-01-25 21 views
3

Хорошо, поэтому я пишу службу журнала, которая записывает некоторые данные в некоторый файл (скажем, имя файла log).Как получить доступ к определенному аргументу, не зная его тип [переменные аргументы] в C?

Тип данных, которые я хочу написать, варьируется, это может быть int или string или что-то еще.

До сих пор это, как моя функция выглядит:

void write_log(FILE * fp, char * event, ...) 
{ 
    va_list list; 
    va_start(list, event); 
    // Cannot use va_arg(list, type_of_var) here!!! 
} 

Так я называю функция может изменяться в зависимости от моих данных:

write_log(fp, "Memory size :", mem_size); 

Или

write_log(fp, "Username :", username); 

У меня есть не знаю, будет ли третий аргумент быть строкой или int или что-то еще.

Я мог бы использовать va_arg(list, type_of_var), но поскольку тип моих данных изменяется произвольно, я не могу его использовать.

Любая идея, как я могу получить доступ к 3-му аргументу функции, не зная ее типа?

+3

Вы не можете. Как вы думаете, почему функции printf требуют строки формата? – DeiDei

+0

Любая идея или обходные пути для моей функции? –

+2

Обходное решение: определите 'struct' с нужными вами полями и передайте его функции, которая записывает файл. Эта функция считывает соответствующие данные из структуры и записывает их в ваш журнал. – ThunderWiring

ответ

4

Нет портативного стандартного способа узнать, что такое типы.

Первым решением, которое приходит на ум, является использование уже известной C-идиомы необходимости передавать строку формата (например, printf, scanf).

void write_log(FILE * fp, char * event, const char* fmt, ...) 
{ 
    va_list list; 
    va_start(list, event); 

    // process fmt and act accordingly 
} 

Если это будет только один дополнительный параметр, то вы можете передать enum:

enum type { 
    integer, 
    pointer, 
    floating 
}; 

void write_log(FILE * fp, char * event, enum type t, ...) 
{ 
    switch(t) 
    { 
    case integer: // do stuff with integer 
    case pointer: // do stuff with pointer 
    } 
} 

Если у вас есть доступ к _Generic возможности C11, поскольку это делает большинство современных компиляторов, вы можете иметь что-то сортировка:

void write_logi(FILE * fp, char * event, int); 
void write_logf(FILE * fp, char * event, float); 
void write_logfoo(FILE * fp, char * event, struct foo); 

#define write_log(file, event, arg) _Generic((arg), \ 
    int: write_logi,        \ 
    float: write_logf,        \ 
    struct foo: write_logfoo      \ 
)(file, event, arg) 

Тогда вы можете назвать как:

write_log(fp, event, i/*int*/); 
write_log(fp, event, f/*float*/); 

и будет выбрана соответствующая функция.

+1

UV для '_Generic', который представляет собой портативный C11 способ узнать, какие типы, хотя и ограничены ранее определенным набором. – chux

+0

Это сработало. Благодаря! –

 Смежные вопросы

  • Нет связанных вопросов^_^