va_arg с указателями - PullRequest
       34

va_arg с указателями

3 голосов
/ 17 мая 2010

Я хочу инициализировать связанный список с аргументами указателя следующим образом:

/* 
 * 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 на va_arg(va, (struct structure *)), и он говорит, что спецификатор типа по умолчанию имеет значение int Он также отмечает экземплярную форму в (struct structure *) и struct structure *. То, что, похоже, присваивается s, равно int (struct structure *).

Прекрасно компилируется, когда скобки удаляются из (struct structure *), но структуры, которые должны быть инициализированы, недоступны.

Почему int предполагается, когда круглые скобки находятся вокруг аргумента типа, передаваемого va_arg? Как я могу это исправить?

Ответы [ 3 ]

5 голосов
/ 17 мая 2010

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);
4 голосов
/ 17 мая 2010

§7.15.1.1 (макрос va_arg) C99 требует:

Параметр type должен быть типом имя указано так, что тип указатель на объект, который имеет указанный тип может быть получен просто отправив * для ввода.

Вот почему круглые скобки здесь не разрешены.

Другие ответы объяснили, почему вам нужно передать struct structure ** и присвоить результат malloc *s.

1 голос
/ 17 мая 2010

Нельзя ставить скобки вокруг типа в va_arg. Вам не нужно. va_arg странный зверь. Практически, это макрос CPP, который расширяется до некоторой разновидности магии для каждого компилятора. Если вы посмотрите на его расширение с помощью вашего компилятора, вы увидите, как это делает ваш компилятор. Что бы это ни было, оно не любит паренов.

...