У програмуванні, фу́нкції зі змі́нним число́м аргуме́нтів називають варіативними.
Існує багато математичних і логічних операцій, які краще реалізувати за допомогою функцій зі змінною кількістю аргументів, наприклад, підсумовування чисел або конкатенація рядків.
Для реалізації функцій зі змінним числом аргументів у мові програмування 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
у C визначається конкретною реалізацією і не зобов'язаний бути нулем, зведеним до типу void *
, а в C++ визначений як 0 без явного зведення до вказівника. Число 0 має тип int
, найменший розмір якого відповідає 16 бітам (2 байти), що, найпевніш, не відповідатиме розміру очікуваного у функції вказівника.
stdarg.h
оголошує тип va_list
, і визначає чотири макрофункції: va_start, va_arg
, va_copy
і va_end
. Кожному виклику va_start і va_copy
має відповідати виклик va_end
. Під час роботи зі змінним числом аргументів функція зазвичай оголошує змінну типу va_list
(ap
у прикладі), якою маніпулюватимуть макроси.
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. Він дублює другий (який повинен був бути ініціалізованим) у перший.