Передача переменного количества аргументов

Скажем, у меня есть функция C, которая принимает 9X_c переменное количество аргументов: как я 9X_variadic-parameter могу вызвать другую функцию, которая ожидает 9X_va-list переменное количество аргументов изнутри, передавая 9X_va-arg все аргументы, которые попали в первую функцию?

Пример:

void format_string(char *fmt, ...); void debug_print(int dbg_lvl, char *fmt, ...) { format_string(fmt, /* how do I pass all the arguments from '...'? */); fprintf(stdout, fmt); } 

353
5

  • Ваш пример кажется мне немного странным, поскольку вы передаете fmt как format_string(), так и fprintf(). Должен ли format_string() каки ...
9
Общее количество ответов: 9

Ответ #1

Ответ на вопрос: Передача переменного количества аргументов

Чтобы передать многоточие, вы как обычно 9X_variadic-functions инициализируете va_list и просто передаете его 9X_varargs второй функции. Вы не используете va_arg(). В частности;

void format_string(char *fmt,va_list argptr, char *formatted_string); void debug_print(int dbg_lvl, char *fmt, ...) { char formatted_string[MAX_FMT_SIZE]; va_list argptr; va_start(argptr,fmt); format_string(fmt, argptr, formatted_string); va_end(argptr); fprintf(stdout, "%s",formatted_string); } 

224
5

  • @fotanus: если вы вызываете функцию с помощью `argptr`, а вызываемая функция вообще использует` argptr`, единственное безопасное решение - это вызвать `va_end()` и затем пере ...

Ответ #2

Ответ на вопрос: Передача переменного количества аргументов

Невозможно вызвать (например) printf, не 9X_variadic-functions зная, сколько аргументов вы ему передаете, если 9X_c только вы не хотите использовать непристойные 9X_va-arg и непереносимые трюки.

Обычно используемое 9X_variable-length-arguments решение - всегда предоставлять альтернативную 9X_variable-length-arguments форму функций vararg, поэтому printf имеет vprintf, который 9X_varargs принимает va_list вместо .... Версии ... - это просто 9X_variadic-parameter оболочки для версий va_list.

62
0

Ответ #3

Ответ на вопрос: Передача переменного количества аргументов

Variadic Functions может быть dangerous. Вот более безопасный трюк:

 void func(type* values) { while(*values) { x = *values++; /* do whatever with x */ } } func((type[]){val1,val2,val3,val4,0}); 

9X_va-arg

53
5

  • @ArtOfWarfare Я не уверен, что согласен с тем, что это плохой хак, у Rose есть отличное решение, но оно включает в себя ввод func ((type []) {val1, val2, 0}); что кажется неуклюжим, если бы у вас #de ...

Ответ #4

Ответ на вопрос: Передача переменного количества аргументов

В великолепном C++ 0x вы можете использовать 9X_variable-length-arguments вариативные шаблоны:

template void format_string(char *fmt, Ts ... ts) {} template void debug_print(int dbg_lvl, char *fmt, Ts ... ts) { format_string(fmt, ts...); } 

30
1

  • Если вы используете Visual Studio, вариативные шаблоны можно добавить в Visual Studio 2012 с помощью C ...

Ответ #5

Ответ на вопрос: Передача переменного количества аргументов

Хотя вы можете решить проблему передачи 9X_va-arg форматировщика, сначала сохранив его в локальном 9X_va-list буфере, но для этого нужен стек, и иногда 9X_va-arg может возникнуть проблема. Я попробовал 9X_va-list подписаться, и, похоже, все работает нормально.

#include #include void print(char const* fmt, ...) { va_list arg; va_start(arg, fmt); vprintf(fmt, arg); va_end(arg); } void printFormatted(char const* fmt, va_list arg) { vprintf(fmt, arg); } void showLog(int mdl, char const* type, ...) { print("\nMDL: %d, TYPE: %s", mdl, type); va_list arg; va_start(arg, type); char const* fmt = va_arg(arg, char const*); printFormatted(fmt, arg); va_end(arg); } int main() { int x = 3, y = 6; showLog(1, "INF, ", "Value = %d, %d Looks Good! %s", x, y, "Infact Awesome!!"); showLog(1, "ERR"); } 

Надеюсь, это 9X_va-arg поможет.

10
0

Ответ #6

Ответ на вопрос: Передача переменного количества аргументов

Вы можете использовать встроенную сборку 9X_variadic-functions для вызова функции. (в этом коде я предполагаю, что 9X_varargs аргументы являются символами).

void format_string(char *fmt, ...); void debug_print(int dbg_level, int numOfArgs, char *fmt, ...) { va_list argumentsToPass; va_start(argumentsToPass, fmt); char *list = new char[numOfArgs]; for(int n = 0; n < numOfArgs; n++) list[n] = va_arg(argumentsToPass, char); va_end(argumentsToPass); for(int n = numOfArgs - 1; n >= 0; n--) { char next; next = list[n]; __asm push next; } __asm push fmt; __asm call format_string; fprintf(stdout, fmt); } 

8
2

  • По крайней мере, это действительно дает ответ на вопрос, не меняя ...

Ответ #7

Ответ на вопрос: Передача переменного количества аргументов

Вы также можете попробовать макрос.

#define NONE 0x00 #define DBG 0x1F #define INFO 0x0F #define ERR 0x07 #define EMR 0x03 #define CRIT 0x01 #define DEBUG_LEVEL ERR #define WHERESTR "[FILE : %s, FUNC : %s, LINE : %d]: " #define WHEREARG __FILE__,__func__,__LINE__ #define DEBUG(...) fprintf(stderr, __VA_ARGS__) #define DEBUG_PRINT(X, _fmt, ...) if((DEBUG_LEVEL & X) == X) \ DEBUG(WHERESTR _fmt, WHEREARG,__VA_ARGS__) int main() { int x=10; DEBUG_PRINT(DBG, "i am x %d\n", x); return 0; } 

9X_variable-length-arguments

8
0

Ответ #8

Ответ на вопрос: Передача переменного количества аргументов

Решение Росса немного улучшилось. Работает 9X_va-arg только в том случае, если все аргументы 9X_variable-length-arguments являются указателями. Также языковая реализация 9X_variable-length-arguments должна поддерживать удаление предыдущей 9X_va-list запятой, если __VA_ARGS__ пуст (как Visual Studio C++, так 9X_c и GCC).

// pass number of arguments version #define callVardicMethodSafely(...) {value_t *args[] = {NULL, __VA_ARGS__}; _actualFunction(args+1,sizeof(args) / sizeof(*args) - 1);} // NULL terminated array version #define callVardicMethodSafely(...) {value_t *args[] = {NULL, __VA_ARGS__, NULL}; _actualFunction(args+1);} 

2
0

Ответ #9

Ответ на вопрос: Передача переменного количества аргументов

Краткий ответ

/// logs all messages below this level, level 0 turns off LOG #ifndef LOG_LEVEL #define LOG_LEVEL 5 // 0:off, 1:error, 2:warning, 3: info, 4: debug, 5:verbose #endif #define _LOG_FORMAT_SHORT(letter, format) "[" #letter "]: " format "\n" /// short log #define log_s(level, format, ...) \ if (level <= LOG_LEVEL) \ printf(_LOG_FORMAT_SHORT(level, format), ##__VA_ARGS__) 

использование

log_s(1, "fatal error occurred"); log_s(3, "x=%d and name=%s",2, "ali"); 

вывод

[1]: fatal error occurred [3]: x=2 and name=ali 

журнал с файлом и номером строки

const char* _getFileName(const char* path) { size_t i = 0; size_t pos = 0; char* p = (char*)path; while (*p) { i++; if (*p == '/' || *p == '\\') { pos = i; } p++; } return path + pos; } #define _LOG_FORMAT(letter, format) \ "[" #letter "][%s:%u] %s(): " format "\n", _getFileName(__FILE__), __LINE__, __FUNCTION__ #ifndef LOG_LEVEL #define LOG_LEVEL 5 // 0:off, 1:error, 2:warning, 3: info, 4: debug, 5:verbose #endif /// long log #define log_l(level, format, ...) \ if (level <= LOG_LEVEL) \ printf(_LOG_FORMAT(level, format), ##__VA_ARGS__) 

использование

log_s(1, "fatal error occurred"); log_s(3, "x=%d and name=%s",2, "ali"); 

вывод

[1][test.cpp:97] main(): fatal error occurred [3][test.cpp:98] main(): x=2 and name=ali 

пользовательская функция печати

вы можете 9X_va-list написать собственную функцию печати и передать 9X_va-arg ей аргументы ..., а также можно комбинировать 9X_variable-length-arguments это с методами, описанными выше. источник 9X_variadic-parameter из here

int print_custom(const char* format, ...) { static char loc_buf[64]; char* temp = loc_buf; int len; va_list arg; va_list copy; va_start(arg, format); va_copy(copy, arg); len = vsnprintf(NULL, 0, format, arg); va_end(copy); if (len >= sizeof(loc_buf)) { temp = (char*)malloc(len + 1); if (temp == NULL) { return 0; } } vsnprintf(temp, len + 1, format, arg); printf(temp); // replace with any print function you want va_end(arg); if (len >= sizeof(loc_buf)) { free(temp); } return len; } 
2
0