假设我有一个带有可变数量参数的C函数:如何调用另一个函数,该函数需要从其内部获取可变数量的参数,并将所有参数传递到第一个函数中?
例:
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); }
SmacL.. 207
要传递省略号,您必须将它们转换为va_list并在第二个函数中使用该va_list.特别;
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); }
代码取自问题,实际上只是如何转换省略号而不是任何功能的说明.如果你看一下它`format_string`也几乎没用,因为它必须对fmt进行原位修改,当然也不应该这样做.选项将包括完全删除format_string并使用vfprintf,但这会假设format_string实际执行的操作,或者format_string返回不同的字符串.我将编辑答案以显示后者. (3认同)
@fotanus:如果用`argptr`调用一个函数,而被调用的函数完全使用`argptr`,唯一安全的做法是调用`va_end()`然后重启`va_start(argptr,fmt);`重新初始化.或者你可以使用`va_copy()`如果你的系统支持它(C99和C11需要它; C89/90没有). (2认同)
小智.. 58
没有办法调用(例如)printf而不知道你传递了多少个参数,除非你想进入顽皮和非便携的技巧.
通常使用的解决方案是始终提供的可变参数的功能的另一种形式,所以printf
具有vprintf
这需要一个va_list
在适当位置的...
.该...
版本只是周围的包装va_list
版本.
要传递省略号,您必须将它们转换为va_list并在第二个函数中使用该va_list.特别;
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); }
没有办法调用(例如)printf而不知道你传递了多少个参数,除非你想进入顽皮和非便携的技巧.
通常使用的解决方案是始终提供的可变参数的功能的另一种形式,所以printf
具有vprintf
这需要一个va_list
在适当位置的...
.该...
版本只是周围的包装va_list
版本.
变异函数可能很危险.这是一个更安全的技巧:
void func(type* values) { while(*values) { x = *values++; /* do whatever with x */ } } func((type[]){val1,val2,val3,val4,0});
在华丽的C++ 0x中,您可以使用可变参数模板:
templatevoid format_string(char *fmt, Ts ... ts) {} template void debug_print(int dbg_lvl, char *fmt, Ts ... ts) { format_string(fmt, ts...); }
您可以使用内联汇编进行函数调用.(在这段代码中我假设参数是字符).
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); }
您也可以尝试使用宏。
#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; }
虽然你可以通过首先将它存储在本地缓冲区中来解决传递格式化程序,但是需要堆栈并且有时可能会处理问题.我试过跟随它似乎工作正常.
#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"); }
希望这可以帮助.