我想知道是否有任何方法可以将参数动态传递给可变参数函数。即如果我有一个功能
int some_function (int a, int b, ...){/*blah*/}
我正在接受用户的一堆值,我想要一些方法将这些值传递给函数:
some_function (a,b, val1,val2,...,valn)
我不想写所有这些功能的不同版本,但我怀疑没有其他选择?
答案 0 :(得分:11)
Variadic函数使用一个调用约定,其中调用者负责从堆栈中弹出函数参数,所以是的,可以动态地执行此操作。它在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);
您可能还会发现this link讨论在C中围绕可变函数生成包装器,以证明为什么它不是标准C的一部分。
答案 1 :(得分:2)
标准方法是让每个可变参数函数伴随va_list
- 采用对应物(如printf和vprintf)。可变版本只是将...
转换为va_list
(使用来自stdarg.h
的宏)并调用其va_list-taking姐妹,它可以完成实际工作。
答案 2 :(得分:1)
尝试传递数组可能会很有趣,然后再使用vararg宏。根据堆栈对齐情况,它可能只是工作(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;
}
答案 3 :(得分: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]);
/* ... */
}