变量参数列表:在变量中收集它们的可能性?

时间:2015-09-15 08:12:28

标签: c variadic-functions

当C函数定义像

这样的变量参数列表时
myfunc(int *i,...);

我可以打电话给它(根据它的正确用法),例如与

myfunc(&i,1,"hello",2,42);

myfunc(&i,"fish",13,33,"haktar",2,42);

但是还有可能在列表中收集这些参数数据,然后将其交给函数吗?意味着有一个可用的变量类型允许这样的东西(伪代码):

arg_list list;

list.add("fish");
list.add(13);
list.add(33);
list.add("haktar");
myfunc(&i,list);

如果是的话:怎么能完全做到这一点?谢谢!

编辑:为了澄清这一点:myfunc(int * i,...)是一个给定的函数原型,无法修改,意味着我必须使用合适的处理“...”参数部分(va_arg-like?)数据类型,我不能使用简单的数组/链表/其他自己的数据类型。

4 个答案:

答案 0 :(得分:2)

您无法直接调用期望变量参数列表的函数。相反,您可以更改函数以接收例如包含允许的参数类型的联合的项目数组:

#include <stdio.h> 

enum arg_type { ARG_TYPE_INTEGER, ARG_TYPE_STRING };

struct arg {
    enum arg_type type;
    union {
        int integer;
        const char *string;
    };
};


static void myfunc(size_t length, struct arg list[length])
{
    for (size_t i = 0; i < length; i++) {
        printf("argument %zu: ", i);
        switch (list[i].type) {
            case ARG_TYPE_INTEGER: printf("integer: %d", list[i].integer); break;
            case ARG_TYPE_STRING: printf("string: %s", list[i].string); break;
        }
        puts("");
    }
}


int main()
{
    struct arg list[] = {
        { .type = ARG_TYPE_STRING, .string = "fish" },
        { .type = ARG_TYPE_INTEGER, .integer = 13 },
        { .type = ARG_TYPE_INTEGER, .integer = 33 },
        { .type = ARG_TYPE_STRING, .string = "haktar" }
    };

    myfunc(sizeof list / sizeof *list, list);
}

(请注意,这使用C11语言功能;您可能需要在编译器中启用C11支持,例如使用clang或gcc的-std=c11选项)

答案 1 :(得分:0)

你的建议是你的函数需要填充某种结构,并将这个结构移交给另一个函数。

我希望这会有所帮助:

#include <stdio.h>

void GetParams(struct list *ptr,char *string1,int a,int b,char *string2);

void myfunc(int *i,struct list List);

struct list
{
char* string1;

int a;

int b;

char* string2;
};

int main(void)
{
int i;

list List;

GetParams(&List,"fish",13,33,"haktar");

myfunc(&i,List);


}

void GetParams(struct list *ptr,char *string1,int a,int b,char *string2)
{
ptr->string1 = string1;

ptr->a = a;

ptr->b = b;

ptr->string2 = string2;
}

void myfunc(int *i,struct list List)
{
*i = 1;
// ...
printf("i : %d\n",*i);

printf("%s\n",List.string1);
printf("%d\n",List.a);
printf("%d\n",List.b);
printf("%s\n",List.string2);
}

答案 2 :(得分:0)

我假设您创建的列表有点像这样

typedef struct arg_list {
    void *data;
    struct arg_list *next;
}

您需要创建一个将参数添加到列表中的函数。

void list_add(arg_list **list, void *data)
{
    arg_list *elem;

    elem = malloc(sizeof(arg_list)); // check what malloc returns

    elem->data = data;
    elem->next = *list;
    *list = elem;
}

这是一个“草图”,别忘了分配你的数据! 这样,您的数据就会添加到列表的开头!

您可以添加以下内容:

list_add(&list, "Hello");
list_add(&list, 42);

编辑:我忘了告诉你如何使用它。

您可以通过list->datalist->next使用它来转到下一个元素。

这称为链表。

答案 3 :(得分:0)

好的,正确答案似乎是:它是不可能的,因为用于变量参数的所有这些va_ * thingies都不是函数或数据类型,而是由预处理器解析的宏。所以这一切似乎只能用静态代码实现,在运行时没有任何改变。