Аргумент переменной перечисляет в функциях C - Как правильно выполнить итерации через список аргумента?

В следующей программе C я получаю предупреждение:

warning #2030: '=' used in a conditional expression.

Какова точно проблема и как я избегаю этого? Чего корректный путь состоит в том, чтобы выполнить итерации через аргументы переменной?

#include <stdio.h>
#include <stdarg.h>

int Sum(int a, int b, ...)
{
    int arg;
    int Sum = a + b;

    va_list ap;
    va_start(ap, b);

    while(arg = va_arg(ap, int))
    {
        Sum += arg;
    }
    va_end(ap);

    return Sum;
}

int main(int argc, char *argv[])
{
    printf("%d\n", Sum(1, 2, 4, 8));

    return 0;
}
5
задан Gary Willoughby 2 January 2010 в 14:29
поделиться

4 ответа

То, что Вы делаете - идиоматическое, если слегка некрасивое C.

Чтобы убедить компилятор, что Вы знаете, что делаете, Вы можете обернуть присваивание в дополнительный набор круглых скобок:

while((arg = va_arg(ap, int)))

Это должно позаботиться о предупреждении.

Обновление:

добавление круглых скобок вокруг присваивания, кажется, не отменяет предупреждение в компиляторе C99, использующем (PellesC). - Гэри Уиллоби

Что, не так? Тогда нужно сделать тест немного более явным:

while((arg = va_arg(ap, int)) != 0)

должен сделать трюк. Также можно поспорить, что он немного более читабельный.


Вы спросите меня, что я имею в виду под "слегка уродливым".

От работы с другими языками я привык к четкому разделению между тестированием и модификацией. Вы делаете тест на этом и значении, но в то же время создаете побочный эффект (а именно читаете в следующем аргументе). Как я уже говорил, на Си это считается вполне нормальным, да "идиоматическим", потому что так делают многие программисты на Си; думаю, в K&R даже есть примеры подобного кода.

По личным предпочтениям я бы, наверное, переписал это так:

while (1) {
  arg = va_arg(ap, int);
  if (!arg) break;
  ...
}

Это четко отделяет присваивание от теста, и позволяет циклу выделяться как (потенциально) бесконечному циклу. Многие посчитали бы мой код более уродливым; как я уже говорил, это вопрос личных предпочтений.

.
5
ответ дан 14 December 2019 в 13:37
поделиться

Предупреждение о:

while(arg = va_arg(ap, int))

и говорит: "Ты уверен, что не имел в виду:"

while(arg == va_arg(ap, int))

В данном случае, ты не сделал этого, чтобы подавить его, сказав:

while( (arg = va_arg(ap, int)) )

Однако, твой код все равно не будет работать. Невозможно использовать вариадические функции, не предоставив каким-то образом количество параметров, представленных элипсисом. Например, printf делает это со знаком %:

printf("%s %d %p", x, y, z );

означает, что элипсис представляет три параметра.

В вашем случае в качестве конечного значения в списке целых чисел, вероятно, можно использовать ноль - это и подразумевается в вашем цикле.

.
1
ответ дан 14 December 2019 в 13:37
поделиться

Еще один способ записи функции:

int Sum(int a, ...)
{
    int sum = 0;
    int current = a;

    va_list args;
    va_start(args, a);

    for(; current; current = va_arg(args, int))
        sum += current;

    va_end(args);

    return sum;
}

Она избавляется от (бесполезного) второго именованного параметра и выводит инкремент указателя аргумента из условия цикла.

.
0
ответ дан 14 December 2019 в 13:37
поделиться

поменять while(arg = va_arg(ap, int)) на while((arg = va_arg(ap, int)))).

Предупреждение выдается потому, что вы присваиваете и проверяете значение присваивания в одном операторе.

.
0
ответ дан 14 December 2019 в 13:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: