如何使用省略号(...)

时间:2015-05-25 13:57:17

标签: c printf

我想在c中编写一个使用elipsis(...)参数的函数,但我不知道它是如何工作的。

我想做这样的事情:

void error(const char* fmt, ...);

void error(const char* fmt, ...) {
  // fprintf(stderr, fmt, ...); << didnt work!
  fprintf(stderr, fmt, /* ??? */);
}

我想像普通的printf()调用一样使用它。

error("bla");
error("nr: %d", 42);
error("pi: %f", 3.1415);

我怎样才能将elipsis作为hole的东西访问并将其传递给下一个函数?

3 个答案:

答案 0 :(得分:2)

如果我理解你的问题,你要找的是关于变量参数或https://developers.google.com/books/docs/overview?csw=1的信息。在C下,您将需要研究'stdargs.h'标题和相关的手册页。这是一个简单的例子,它采用任意数量的整数并返回平均值。

#include <stdarg.h>

float average(int v, ...)
{
    va_list args;
    int i = 0;
    int num = 0;

    va_start(args, v);
    for (; v; v--){
        i += va_arg(args, int);
        num++;
    }
    va_end(args);
    return (float)i/num;
}

答案 1 :(得分:2)

省略号不构成您可以直接处理或转发的任何方式的“包”。管理与任何函数参数不匹配的函数参数的唯一方法是通过<stdarg.h>功能。

这意味着对于每个变量函数foo,您还应始终使用消耗vfoo的相应函数va_list。例如:

#include <stdarg.h>

void foo(const char * fmt, ...);
void vfoo(const char * va_list ap);

前者通常以后者的形式实施:

void foo(const char * fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    vfoo(fmt, ap);
    va_end(ap);
}

幸运的是,printf系列函数遵循这些规则。因此,当您想要转移到printf函数时,实际上使用了相应的基础vprintf版本:

void error(const char * fmt, ...)
{
    do_stuff();

    va_list ap;
    va_start(ap, fmt);

    vfprintf(stderr, fmt, ap);

    va_end(ap);
}

当然遵循相同的规则,您应首先编写verror函数,然后拨打vprintf

void verror(const har * fmt, va_list ap)
{
    do_stuff(); 
    vfprintf(stderr, fmt, ap);
}

答案 2 :(得分:2)

有关处理具有可变参数的函数,请参阅stdarg.h

对于简单地将可变数量的参数传递给fprintf的特定情况,有vfprintf,例如,

void error (const char *fmt, ...) {
    va_list args;
    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    va_end(args);
}

对于这种简单的情况,你也可以考虑变量宏(在C99中引入),例如,

#define error(fmt, ...) fprintf(stderr, "Error: " fmt, __VA_ARGS__)