Вариативная функция
В программировании функции с переменным числом аргументов называются вариативными.
Существует множество математических и логических операций, которые лучше реализовать с помощью функций с переменным количеством аргументов, например, суммирование чисел или конкатенация строк.
Пример в Си
Для реализации функций с переменным числом аргументов в языке программирования C нужно подключить заголовочный файл stdarg.h
. Прежде использовался varargs.h
, который был объявлен устаревшим. Для C++ этот заголовочный файл называется cstdarg
[1].
#include <stdarg.h>
double average(int count, ...)
{
va_list ap;
int j;
double sum = 0;
va_start(ap, count); /* Требуется последний известный аргумент (чтобы получить адрес первого неизвестного) */
for (j = 0; j < count; j++) {
sum += va_arg(ap, double); /* Увеличивает ap до следующего аргумента. */
}
va_end(ap);
return sum / count;
}
Эта функция позволяет вычислить среднее значение от произвольного количества аргументов. Обратите внимание, что функция не знает число аргументов и их типы. Функция из примера выше ожидает, что типы будут double
и то, что число параметров передаётся в первом аргументе. В других случаях, например для функции printf(), число и типы аргументов выясняются из строки формата.
В общем случае стоит знать о правиле повышения типов по умолчанию, согласно которому повышению типа подвержены все аргументы функции, включая неизвестные аргументы. Так, если бы в примере выше неизвестные аргументы были бы объявлены типа float
, фактически они бы оказались типа double
, и ожидать функция должна была бы тип double
, а не float
. Это может внести путаницу и ошибки, если функция ожидает аргумент определенной размерности, а получает аргумент другой размерности. Особенно опасным является использование макроса NULL
в вариативных функциях, поскольку NULL
в Си определяется конкретной реализацией и не обязан быть нулём, приведённым к типу void *
, а в C++ определён как 0 без явного приведения к указателю. Число 0 имеет тип int
, минимальный размер которого соответствует 16 битам (2 байта), что, скорее всего, будет не соответствовать размеру ожидаемого в функции указателя.
stdarg.h
объявляет тип va_list
, и определяет четыре макрофункции: va_start, va_arg
, va_copy
и va_end
.
va_start
принимает два аргумента, объектva_list
и ссылку на последний параметр функции (тот, что перед многоточием). Она инициализируетva_list
объект для использования вva_arg
илиva_copy
. Компилятор обычно выдает предупреждение, если ссылка неверная (например, ссылка на параметры, отличающиеся от последнего, или ссылка на совершенно другой объект).va_arg
принимает два аргумента,va_list
объект (ранее инициализированный) и дескриптор типа. Он расширяется на следующей переменной аргумент, и имеет указанный тип. Каждый следующий вызов возвращает следующий аргумент.va_end
принимает один аргумент типаva_list
и очищает его. Если вы хотели, например, сканировать переменное число аргументов более чем один раз, вам надо будет повторно инициализироватьva_list
путём вызоваva_end
и затемva_start
.va_copy
принимает два аргумента, оба типа va_list. Он дублирует второй (который должен был быть инициализирован) в первый.
См. также
- Макрос с переменным числом аргументов (язык программирования Си)
- Вариативный шаблон
Примечания
Ссылки
- Variadic function. Rosetta Code task showing the implementation of variadic functions in over fifty programming languages.
- Variable Argument Functions — A tutorial on Variable Argument Functions for C++
- GNU libc manual