Работа с неопределённым числом параметров

Синтаксиз

Язык C предостовляет возможность работать с неопределённым числом параметров в функциях. Синтаксиз объявления функции следующий.

Копировать
тип_возврата имя_функции(список_основных_параметров,
			тип_данных имя_параметра, ...)

Здесь первый параметр имя_параметра необходим обозначения имени списка параметров и последующей ссылки обработчиками на список.

Макросы-обработчики

Обработка параметров происходит при помощи следующих макросов
• va_start() — указатель списка параметров
• va_arg() — берёт аргумент из списка параметров
• va_end() — закрывает указатель списка параметров
• va_copy() — копирует список аргументов в объект

Они объявлены в загаловке <stdarg.h> и их синтаксиз следующий

Копировать
type va_arg(va_list argptr, type);
void va_copy(va_list target, va_list source);
void va_end(va_list argptr);
void va_start(va_list argptr, last_parm);

Макросы va_arg, va_start и va_end работают вместе, чтобы сделать возможной передачу функции переменного числа аргументов. Самым распространенным примером функции, которая принимает переменное число аргументов, является функция printf(). Тип va_list определен в заголовке <stdarg.h>(а в среде языка C++ — в заголовке <cstdarg>).

Описание

Общая процедура создания функции, которая может принимать переменное количество аргументов, такова. Функция должна иметь по крайней мере один известный параметр(может и больше), указываемый до переменного списка параметров. Крайний справа известный параметр называется last_parm. Его имя используется в качестве второго параметра в обращении к макросу va_start(). Прежде чем можно будет получить доступ к любому параметру из списка параметров переменной длины, необходимо инициализировать указатель на аргумент argptr, обратившись к макросу va_start(). После этого параметры возвращаются посредством обращения к макросу va_arg() с передачей значения параметра type, которое представляет собой тип следующего параметра. Наконец после прочтения всех параметров до возвращения из функции необходимо вызвать макрос va_end(), чтобы гарантировать корректное восстановление стека. Если макрос va_end() не вызывается, высока вероятность аварийного отказа программы.

Пример

В следующей программе применяется функция sum_series(), которая возвращает сумму ряда чисел. Первый аргумент содержит количество аргументов, перечисленных за ним. В этом примере суммируются первые пять элементов следующего ряда чисел.

Копировать
1     1     1      1          1
-  +  -  +  -  +  ——  ...  +  -
2     4     8     16          2n

Результат равен 0.968750.

Копировать
/* Пример списка аргументов переменной длины сумма ряда . * /

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

double sum_series(int, ...);

int main(void)
{
	double d;

	d = sum_series(5, 0.5, 0.25, 0.125, 0.0625, 0.03125);
	printf("Сумма ряда равна %f\n",d);

	return 0;
}

double sum_series(int num, ...)
{
	double sum = 0.0, t;
	va_list argptr;

	/* Инициализируем указатель argptr. */
	va_start(argptr, num);

	/* Суммируем ряд. */
	for(; num; num--) {
		t = va_arg(argptr, double);
		sum += t;
	}

	/* Реализуем корректное завершение. */
	va_end(argptr);

	return sum;
}