Передача переменного количества аргументов
Скажем, у меня есть функция 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);
}
- Ваш пример кажется мне немного странным, поскольку вы передаете fmt как format_string(), так и fprintf(). Должен ли format_string() каки ...
Ответ #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);
}
- @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
.
Ответ #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
- @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...);
}
- Если вы используете 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 поможет.
Ответ #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);
}
- По крайней мере, это действительно дает ответ на вопрос, не меняя ...
Ответ #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
Ответ на вопрос: Передача переменного количества аргументов
Решение Росса немного улучшилось. Работает 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);}
Ответ #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__)
/// 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;
}
-
22
-
6
-
3
-
3
-
7
-
14
-
6
-
8
-
2
-
9
-
4
-
7
-
15
-
10
-
5
-
2
-
2
-
2
-
8
-
2
-
5
-
5
-
9
-
9
-
13
-
6
-
3
-
6
-
6
-
2
-
3
-
4
-
5
-
2
-
4
-
2
-
2
-
6
-
8
-
1
-
4
-
1
-
2
-
4
-
1
-
6
-
2
-
1
-
2
-
6