В следующей программе 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;
}
То, что Вы делаете - идиоматическое, если слегка некрасивое 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;
...
}
Это четко отделяет присваивание от теста, и позволяет циклу выделяться как (потенциально) бесконечному циклу. Многие посчитали бы мой код более уродливым; как я уже говорил, это вопрос личных предпочтений.
.Предупреждение о:
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 );
означает, что элипсис представляет три параметра.
В вашем случае в качестве конечного значения в списке целых чисел, вероятно, можно использовать ноль - это и подразумевается в вашем цикле.
.Еще один способ записи функции:
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;
}
Она избавляется от (бесполезного) второго именованного параметра и выводит инкремент указателя аргумента из условия цикла.
. поменять while(arg = va_arg(ap, int))
на while((arg = va_arg(ap, int))))
.
Предупреждение выдается потому, что вы присваиваете и проверяете значение присваивания в одном операторе.
.