将参数动态传递给可变参数函数

我想知道是否有任何方法可以动态地将参数传递给可变参数函数。 即如果我有一个function

int some_function (int a, int b, ...){/*blah*/} 

我接受用户的一堆值,我想要一些方法将这些值传递给函数:

 some_function (a,b, val1,val2,...,valn) 

我不想写所有这些function的不同版本,但我怀疑没有其他选择?

变量函数使用调用约定,其中调用者负责从堆栈弹出函数参数,所以是的,可以动态地执行此操作。 它在C中没有标准化,通常需要一些程序集来手动推送所需的参数,并正确调用可变参数函数。

cdecl调用约定要求以正确的顺序推送参数,并且在调用之后,弹出在调用之前作为参数推送的字节。 通过这种方式,被调用函数可以接收任意数量的参数,因为调用者将处理将堆栈指针恢复为其预调用状态。 在...之前的参数占用的空间是推送的字节数的安全下限。 在运行时解释其他可变参数。

FFCALL是一个库,它提供了将参数动态传递给可变参数函数的包装器。 您感兴趣的function组是avcall 。 这是一个调用上面给出的函数的示例:

 #include  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中围绕可变函数生成包装器,以certificate为什么它不是标准C的一部分。

一种标准的方法是让每个可变参数函数都附带一个va_list -taking对应物(如printf和vprintf)。 可变版本只是将...转换为va_list (使用来自stdarg.h宏)并调用其va_list-taking姐妹,它可以完成实际工作。

尝试传递数组可能会很有趣,然后再使用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; } 

根据你传递的内容,它可能是你在这之后的一个有区别的联盟(正如评论中暗示的那样)。 这样可以避免使用可变函数或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]); /* ... */ }