将省略号传递给另一个可变参数函数

75

我大约有30个变长参数函数。每个函数都接受一个路径作为最后一个参数,例如:

bool do_foo(struct *f, int q, const char *fmt, ...)
在每个函数中,我都必须检查扩展格式是否小于或等于某个大小。因此,我发现自己在复制/粘贴相同的代码块以检查有多少字符 vsnprintf() 没有打印,根据情况设置 errno 并退出写操作。
我想做的是编写一个函数来做这件事,它将返回已知为安全大小的静态分配(扩展)字符串,或在失败时返回新初始化的字符串,可以针对 NULL 进行检查。检查还必须确定字符串是绝对路径还是相对路径,这会影响字符串的安全大小。这是很多重复的代码,而且开始出现问题了。
是否有一种方法可以将 ellipsis 的内容从我的函数输入传递到另一个函数?还是我必须首先调用 va_start(),然后将 va_list 传递给帮助程序函数?
编辑:
我完全不反对将 va_list 传递给辅助程序,只是想确保没有其他东西存在。在我看来,编译器了解可变参数从哪里开始,所以我只是好奇能否告诉它将它们一起传递。

你有什么不愿意将 va_list 传递给 helper 的理由吗? - ojblass
我曾经也不得不做类似的事情,但是不得不去除一些参数……这不是很容易维护的代码。 - ojblass
4个回答

75
你不能这样做,你只能将参数作为va_list传递。请参考comp.lang.c FAQ
一般来说,如果你在C语言中编写可变参数函数(即接受可变数量的参数的函数),你应该编写两个版本的每个函数:一个接受省略号(...),另一个接受va_list。接受省略号的版本应该调用va_start,调用接受va_list的版本,调用va_end,然后返回。在这两个函数版本之间没有必要重复代码,因为一个版本调用另一个版本。
一个简单的用例可能是:
int vadd(int num_count, va_list args) {
    int sum = 0;
    for(int k = 0; k < num_count; k++) {
        sum += va_arg(args, int);
    }

    return sum;
}

int add(int num_count, ...) {
    va_list args;
    int sum = 0;

    va_start(args, num_count);
    sum = vadd(num_count, args);
    va_end(args);

    return sum;
}

19
请提供代码。 - Andrew Rasmussen
如果我需要两次使用 va_list ,该怎么办? 通常情况下,在使用之间我需要调用 va_endva_start(否则就是UB),但我不能在一个带有 va_list 的函数中调用它: ‘va_start’ used in function with fixed args. - rr-
2
没事了,我已经想通了 - 我需要在每次后续使用时使用 va_copy - rr-
代码?这里也是帮助他人的地方! - Vassilis
真遗憾,C/C++不支持这个。 - Kiruahxh

12

可能可以使用可变参数宏 - 像这样:

#define FOO(...)  do { do_some_checks; myfun(__VA_ARGS__); } while (0)

NB! 可变参数宏仅适用于C99


我正在看那些,这让我不必在实际执行写操作的函数周围添加包装器。 - Tim Post
C99没有问题,我的程序更偏向于GCC / Linux。 - Tim Post

1

我不知道这是否有帮助,您可以通过引用访问变量。这是一种有点狡猾的技巧,但不幸的是它不能允许您在最终函数定义中使用省略号。

#include <stdio.h>

void print_vars(int *n)
{
  int i;
  for(i=0;i<=*n;i++)
    printf("%X %d  ", (int)(n+i), *(n+i));
  printf("\n");
}

void pass_vars(int n, ...)
{
  print_vars(&n);
}

int main()
{
    pass_vars(4, 6, 7, 8, 0);
    return 0;
}

在我的电脑上,它输出

$ ./a.out
BFFEB0B0 4  BFFEB0B4 6  BFFEB0B8 7  BFFEB0BC 8  BFFEB0C0 0

11
不具备可移植性... - aschepler

0

你需要将va_list传递给辅助函数。


1
这个答案过于简洁,没有实际用处。应该加入更多有用的细节或直接删除。 - Richard Stelling
@rjstelling 我在提问时发现这个答案很有用。如果你注意到的话,我表明我基本上同意传递va_list,但感觉可能有不同的方法来做。Andrew基本上确认了没有其他方法(我可以使用的编译器魔法)。虽然其他答案深入探讨了更多,但这个答案已经足够回答我的问题。 - Tim Post

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接