C 将参数动态传递给变量函数

C 将参数动态传递给变量函数,c,dynamic,argument-passing,variadic,C,Dynamic,Argument Passing,Variadic,我想知道是否有任何方法可以将参数动态地传递给可变函数。i、 如果我有一个函数 int some_function (int a, int b, ...){/*blah*/} 我接受用户提供的一组值,我想用某种方式将这些值传递到函数中: some_function (a,b, val1,val2,...,valn) 我不想编写所有这些函数的不同版本,但我怀疑没有其他选择?尝试只传递一个数组,然后使用vararg宏可能会很有趣。根据堆栈对齐情况,它可能只起作用(tm) 这可能不是一个最佳的解决方

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

int some_function (int a, int b, ...){/*blah*/}
我接受用户提供的一组值,我想用某种方式将这些值传递到函数中:

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

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

尝试只传递一个数组,然后使用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;
}

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

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

是一个提供包装器的库,用于将参数动态传递给可变函数。您感兴趣的函数组是。下面是一个调用上述函数的示例:

#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_列表
-取对应的变量(如printf和vprintf)。可变版本只是将
..
转换为
va_列表
(使用
stdarg.h
中的宏),并调用其va_列表接受姐妹,该姐妹进行实际工作。

根据您传递的内容,它可能是一个有区别的联盟(如注释中所暗示的)。这将避免对变量函数或void*
数组的需要,并回答了“某个函数如何知道您实际传递了什么”的问题。您可能有如下代码:

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:
      /* ... */
    }
}
您可以更进一步,通过将
代码
替换为一个或多个指向函数的指针来避免切换,这些函数对每件
事情都有用。例如,如果您想做的是简单地打印出每一件事情,您可以有:

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]);
  /* ... */
}

它不会工作,因为数组不是按值传递的,而是指针true——当我想出来的时候,我想以某种方式将数组推到堆栈上。但是如果你只是将数组传递给一个函数,C就不会这样做——你必须自己做。当使用结构来包装数组时,它至少有可能工作:)请参见示例如果所有值都是相同类型的(正如你的问题似乎暗示的那样-如果我错了,请纠正我)我建议根本不要使用变量函数,而是传递一个数组;请参阅此处,了解一些宏魔术,以便在传入固定数量的参数时对其进行优化:不,它们是不同类型的。@tommobh:如果将值包装在并集中,或者将
void*
数组传递给值,而不是值本身,则数组方法仍然可以工作,但会少一些elegant@Christoph:传递一个void*数组听起来像是一个理想的解决方案。事实上,我不认为这会起作用。谢谢,我会研究这个方法。@atzz但同样的问题。我仍然需要动态地向函数添加参数,不管它是否调用它的va_list-taking姐妹函数。你的意思是我将这些值转换成va_列表,然后使用va_列表的姐妹函数吗?@tommobh——我想我对你的问题的解释是错误的。通过阅读注释,我认为您有一种方法可以获得不同类型的值(例如,从gui),并且需要将它们传递给函数;对吗?在这种情况下,va_列表不会有多大帮助。如果你不想依赖黑客,你必须改变函数…@Anacrolix你说的“并适当地调用varargs调用”是什么意思?该函数处理varargs。@Anacrolix谢谢,非常感谢。我认为重要的是要提到该库是GPL 3,这使得它在很多情况下都不适用。@Ned:我使用的变量函数在一个我理想情况下不想更改的库中(即,我不想更改“某些函数()”)。用户可以输入任意数量的任意类型(在合理范围内),因此定义严格的联合似乎不起作用。一系列void*或Anacrolix的建议似乎是我最好的选择。或者我写了一些内联汇编:S。但是如果你不能改变某个函数,你怎么能给它传递一个void*数组呢?这里的用户指的是使用您的代码的开发人员,还是程序的最终用户?@Ned:user=end user。是的,我明白你的意思了。我不想改变函数,因为函数本身调用了另一个变量函数,我也必须改变它。那只会像滚雪球一样。我感觉我回到了我开始的地方。