填充va_list

kri*_*ina 25 c variadic-functions

有没有办法va_list从头开始创建?我正在尝试调用一个va_list带有参数的函数:

func(void **entry, int num_args, va_list args, char *key); 
Run Code Online (Sandbox Code Playgroud)

...来自不采用可变数量参数的函数.我能想到的唯一方法是创建一个中间函数,它接受varargs然后传递它的va_list,这是非常愚蠢的:

void stupid_func(void **entry, char *key, int num_args, ...) {
    va_list args;
    va_start(args, num_args);

    func(entry, num_args, args, key);

    va_end(args);
}
Run Code Online (Sandbox Code Playgroud)

有没有更好的办法?我不能改变func签名.

Aid*_*ell 14

这是一个坏主意,因为va_list抽象是为了隐藏有关堆栈指针的一些严格的编译器/体系结构特定细节而不是.一旦初始化,它几乎与函数的范围有关.如果你缠绕堆栈并引用前一帧va_args超出范围,事情可能会变坏.你可以传递它们但......

期待虫子

请参阅:http://lists.freebsd.org/pipermail/freebsd-amd64/2004-August/001946.html

还要检查man(3)va_copy和朋友,以便更安全地处理va_args并传递它们.

恕我直言va_args的东西不是很整洁.在过去,我通过初始化堆上的结构/不透明指针然后使用指针算法来处理数据来解决这个问题.但这是一个黑客,取决于具体情况.


Nik*_*sov 6

我理解并同意艾登的警告 - va_list因为他们隐藏了低级别的召唤惯例,所以朋友很危险.但是......在这种情况下,我认为你别无选择.将static ...函数放入.c文件中,以便其他任何人都无法看到它,对您需要调用的函数进行代理,测试它的地狱,然后完成.只是确保不要在调用链上公开可变参数.


RBe*_*eig 5

您创建代理函数的想法va_list是正确的方法.该代理不需要具有公共范围.但是,如果您可能发现代理已存在.例如,在许多库实现sprintf()中只是代理vsprintf().

除非您愿意将代码绑定到特定的编译器和目标平台,否则没有更好的方法.定义的名称<stdarg.h>用于提供可移植且一致的接口,以支持对可变参数列表的访问.实现和使用可变参数函数的唯一可移植方法是通过该接口.

也就是说,你有可能通过复制数组中的调用框架并手工构造一个va_list正确引用它的框架来牺牲可移植性.结果将永远不可移植.


ntd*_*ntd 5

stupid_func是完全有效的 C 代码,否则你怎么会调用vprintf和类似的函数?

glib广泛使用这些包装器。C99 规范本身在示例中也有类似的内容。摘自第7.19.6.8节:

下面显示了 vfprintf 函数在一般错误报告例程中的使用。

#include <stdarg.h>
#include <stdio.h>
void error(char *function_name, char *format, ...)
{
    va_list args;
    va_start(args, format);
    // print out name of function causing error
    fprintf(stderr, "ERROR in %s: ", function_name);
    // print out remainder of message
    vfprintf(stderr, format, args);
    va_end(args)
}
Run Code Online (Sandbox Code Playgroud)