当前位置:  开发笔记 > 编程语言 > 正文

传递可变数量的参数

如何解决《传递可变数量的参数》经验,为你挑选了7个好方法。

假设我有一个带有可变数量参数的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版本.



1> SmacL..:

要传递省略号,您必须将它们转换为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返回不同的字符串.我将编辑答案以显示后者.
@fotanus:如果用`argptr`调用一个函数,而被调用的函数完全使用`argptr`,唯一安全的做法是调用`va_end()`然后重启`va_start(argptr,fmt);`重新初始化.或者你可以使用`va_copy()`如果你的系统支持它(C99和C11需要它; C89/90没有).

2> 小智..:

没有办法调用(例如)printf而不知道你传递了多少个参数,除非你想进入顽皮和非便携的技巧.

通常使用的解决方案是始终提供的可变参数的功能的另一种形式,所以printf具有vprintf这需要一个va_list在适当位置的....该...版本只是周围的包装va_list版本.



3> Rose Perrone..:

变异函数可能很危险.这是一个更安全的技巧:

   void func(type* values) {
        while(*values) {
            x = *values++;
            /* do whatever with x */
        }
    }

func((type[]){val1,val2,val3,val4,0});


更好的是这个技巧:`#define callVardicMethodSafely(values ...)({values*v = {values}; _actualFunction(values,sizeof(v)/ sizeof(*v));})`
如果你想传递0作为参数怎么办?
@ RichardJ.RossIII我希望你能扩展你的评论,它几乎不可读,我无法弄清楚代码背后的想法,它实际上看起来非常有趣和有用.
@ArtOfWarfare我不确定我是否认为它是一个糟糕的黑客,Rose有一个很好的解决方案,但它涉及输入func((type []){val1,val2,0}}; 如果你有#define func_short_cut(...)func((type []){__ VA_ARGS__}),那感觉很笨拙 然后你可以简单地调用func_short_cut(1,2,3,4,0); 它提供了与普通可变函数相同的语法,并具有Rose的巧妙技巧的附加好处......这里的问题是什么?

4> user2023370..:

在华丽的C++ 0x中,您可以使用可变参数模板:

template 
void format_string(char *fmt, Ts ... ts) {}

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



5> 小智..:

您可以使用内联汇编进行函数调用.(在这段代码中我假设参数是字符).

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);
    }


至少这实际上回答了这个问题,而没有重新定义问题.
新的没有删除.
不可移植,取决于编译器,并阻止编译器优化.很糟糕的解决方案

6> GeekyJ..:

您也可以尝试使用宏。

#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;
}



7> VarunG..:

虽然你可以通过首先将它存储在本地缓冲区中来解决传递格式化程序,但是需要堆栈并且有时可能会处理问题.我试过跟随它似乎工作正常.

#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");
}

希望这可以帮助.

推荐阅读
勤奋的瞌睡猪_715
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有