Сведения о том, как аргументы передаются в функцию, являются «соглашением о вызовах». В зависимости от платформы, языка и компилятора правила могут быть сложными. Поэтому небезопасно предполагать, что x_1
находится в стеке, а *(ptr + 1)
является первым аргументом после x_1
. Цель stdarg.h - предоставить переносимый способ перебора аргументов переменной.
Чтобы использовать stdarg.h, функции нужны три вещи:
- Как минимум одно исправленное аргумент
- Способ определения количества переменных аргументов
- Способ определения типа каждой переменной arugment
Функции типа printf
имеют строку формата это и фиксированный аргумент, и он кодирует число и тип каждого аргумента переменной.
Для value
первый аргумент n
является фиксированным аргументом и дает число переменных аргументов. Не существует четкого способа определить тип каждого аргумента переменной для value
. Один из вариантов - сделать выбор, например, «int», и документировать функцию. Поскольку операция внутри for-l oop является делением, возможно, имеет смысл использовать float или double.
Использование stdarg.h в этом случае прямолинейно. Используйте va_start
для инициализации va_list
, а затем используйте va_arg
для получения значения каждого аргумента переменной.
/* value inputs n variable arguments, call them x_i, of type int
* and returns the value
*
* (x_0 / x_1) + (x_2 / x_3) + ...
*
* n must be even
* the division is integer division
*/
int value(int n, ...)
{
int result = 0;
va_list ap;
va_start(ap, n);
for (int i = 0; i < n/2; ++i) {
int a = va_arg(ap, int);
int b = va_arg(ap, int);
result += a/b;
}
va_end(ap);
return result;
}
Пример вызовов
В этом примере вычисляется (6/3) + (21/7):
int r = value(4, 6, 3, 21, 7);
printf("%d\n", r);
и приводит к
5
Во втором примере показано, что value
можно вызвать, распаковав массив
int a[] = {49, 7, 64, 8, 121, 11};
int r = value(6, a[0], a[1], a[2], a[3], a[4], a[5]);
printf("%d\n", r);
, что приводит к
26