带指针的va_arg

时间:2010-05-16 21:53:30

标签: c linked-list c99 variadic-functions

我想用指针参数初始化链表,如下所示:

/* 
 * Initialize a linked list using variadic arguments
 * Returns the number of structures initialized
 */
int init_structures(struct structure *first, ...) 
{
    struct structure *s;
    unsigned int count = 0;
    va_list va;
    va_start(va, first);

    for (s = first; s != NULL; s = va_arg(va, (struct structure *))) {
        if ((s = malloc(sizeof(struct structure))) == NULL) {
            perror("malloc");
            exit(EXIT_FAILURE);
        }
        count++;
    }

    va_end(va);

    return count;
}

问题是type name requires a specifier or qualifier处的clang错误va_arg(va, (struct structure *)),并且说类型说明符默认为int。它还记录了(struct structure *)struct structure *的实例化表单。这似乎分配给s的内容是int (struct structure *)

当从(struct structure *)中删除括号时,它编译得很好,但是应该初始化的结构是不可访问的。

当括号围绕传递给va_arg的类型参数时,为什么会假设int?我该如何解决这个问题?

3 个答案:

答案 0 :(得分:5)

va_arg是许多系统上的宏,显然struct structure *周围的括号会导致宏扩展,因此无法解析。所以不要这样做。

这与您的初始化结构“无法访问”的原因无关。您正在分配结构并将其分配给s,但s是一个局部变量。您不能通过分配局部变量来影响调用者中的值。要完成你想要做的事情,调用者需要传递一个指向指针的指针,然后你可以初始化

int init_structures(struct structure **first, ...) 
{
    struct structure **s;
    unsigned int count = 0;
    va_list va;
    va_start(va, first);

    for (s = first; s != NULL; s = va_arg(va, struct structure **)) {
        if ((*s = malloc(sizeof(struct structure))) == NULL) {
            perror("malloc");
            exit(EXIT_FAILURE);
        }
        count++;
    }

    va_end(va);

    return count;
}

调用者应该这样做:

struct structure *a, *b;
init_structures(&a, &b, NULL);

答案 1 :(得分:4)

C99

§7.15.1.1(va_arg宏)要求:

  

参数 type 应为类型   名称指定为a的类型   指向具有该对象的对象的指针   特定类型可以简单地获得   通过post fi xing a *来输入。

这就是为什么不允许使用括号的原因。

其他答案解释了为什么您需要传递struct structure **并将malloc结果分配给*s

答案 2 :(得分:1)

你不能在va_arg中的类型周围放置parens。你不需要。 va_arg是一个奇怪的野兽。实际上,它是一个CPP宏,可以扩展到某种编译器时的魔力。如果您使用编译器查看它的扩展,您将看到编译器如何执行它。无论是什么,它都不喜欢parens。