我想知道是否有任何方法可以动态地将参数传递给可变参数函数。即如果我有一个功能
int some_function (int a, int b, ...){/*blah*/}
我正在接受来自用户的一堆值,我想要某种方式将这些值传递给函数:
some_function (a,b, val1,val2,...,valn)
我不想编写所有这些函数的不同版本,但我怀疑没有其他选择?
我想知道是否有任何方法可以动态地将参数传递给可变参数函数。即如果我有一个功能
int some_function (int a, int b, ...){/*blah*/}
我正在接受来自用户的一堆值,我想要某种方式将这些值传递给函数:
some_function (a,b, val1,val2,...,valn)
我不想编写所有这些函数的不同版本,但我怀疑没有其他选择?
可变参数函数使用调用约定,调用者负责从堆栈中弹出函数参数,所以是的,可以动态地执行此操作。它在 C 中没有标准化,通常需要一些程序集来手动推送所需的参数,并正确调用可变参数函数。
调用约定要求以正确的cdecl
顺序推送参数,并且在调用之后,弹出调用之前作为参数推送的字节。通过这种方式,被调用函数可以接收任意数量的参数,因为调用者将处理将堆栈指针恢复到其调用前状态。之前的参数占用的空间...
是推送字节数的安全下限。额外的可变参数在运行时被解释。
FFCALL是一个库,它提供了将参数动态传递给可变参数函数的包装器。您感兴趣的函数组是avcall。这是一个调用您上面给出的函数的示例:
#include <avcall.h>
av_alist argList;
int retVal;
av_start_int(argList, some_function, retval);
av_int(argList, a);
av_int(argList, b);
av_type(argList, val1);
...
av_type(argList, valn);
av_call(argList);
您可能还会发现此链接讨论在 C 中围绕可变参数函数生成包装器,以证明为什么这不是标准 C 的一部分。
一个标准的方法是让每个可变参数函数都伴随着一个va_list
-take 对应物(如在 printf 和 vprintf 中)。可变参数版本只是转换...
为 a va_list
(使用来自 的宏stdarg.h
)并调用它的 va_list-taking 姊妹,它确实有效。
尝试只传递一个数组,然后使用可变参数宏可能会很有趣。根据堆栈对齐,它可能只是工作(tm)。
这可能不是最佳解决方案,我主要发布它是因为我发现这个想法很有趣。尝试后,这种方法适用于我的 linux x86,但不适用于 x86-64 - 它可能可以改进。此方法将取决于堆栈对齐、结构对齐等等。
void varprint(int count, ...)
{
va_list ap;
int32_t i;
va_start(ap, count);
while(count-- ) {
i = va_arg(ap, int32_t);
printf("Argument: %d\n", i);
}
va_end(ap);
}
struct intstack
{
int32_t pos[99];
};
int main(int argc, char** argv)
{
struct intstack *args = malloc(sizeof(struct intstack));
args->pos[0] = 1;
args->pos[1] = 2;
args->pos[2] = 3;
args->pos[3] = 4;
args->pos[4] = 5;
varprint(5, *args);
return 0;
}
根据您传递的内容,它可能是您在这里追求的受歧视的工会(如评论中所暗示的那样)。这将避免对可变参数函数或数组的需求void*
,并回答“ some_function 如何知道您实际传递给它的内容”的问题。你可能有这样的代码:
enum thing_code { INTEGER, DOUBLE, LONG };
struct thing
{
enum thing_code code;
union
{
int a;
double b;
long c;
};
};
void some_function(size_t n_things, struct thing *things)
{
/* ... for each thing ... */
switch(things[i].code)
{
case INTEGER:
/* ... */
}
}
您可以更进一步,通过将 替换为code
一个或多个指向函数的指针来避免切换,这些函数对每个 执行一些有用的操作thing
。例如,如果你想做的是简单地打印出每一件事,你可以这样:
struct thing
{
void (*print)(struct thing*);
union
{
...
};
}
void some_function(size_t n_things, struct thing *things)
{
/* .. for each thing .. */
things[i]->print(things[i]);
/* ... */
}