Функции с переменным числом аргументов в C: практическое руководство
Иногда нужно написать функцию, принимающую переменное количество аргументов (как printf). В C это делается через эллипсис (...) и макросы из заголовочного файла <stdarg.h>.
Объявление такой функции
int func(int count, ...); // последний параметр — ..., перед ним int — число аргументов
Параметр перед ... (обычно int) по соглашению указывает количество последующих аргументов.
Пошаговая работа с va_list
- Объявите переменную типа va_list (определён в
stdarg.h). - Инициализируйте её макросом va_start(va_list, last_fixed_param).
- Получайте аргументы макросом va_arg(va_list, type) — каждый вызов возвращает следующий аргумент заданного типа.
- Завершите работу макросом va_end(va_list) (очищает память).
Пример: функция average()
#include <stdio.h>
#include <stdarg.h>
double average(int num, ...) {
va_list args;
double sum = 0.0;
va_start(args, num);
for (int i = 0; i < num; i++) {
sum += va_arg(args, int); // предполагаем, что все аргументы int
}
va_end(args);
return sum / num;
}
int main() {
printf("Average of 2, 3, 4, 5 = %f\n", average(4, 2, 3, 4, 5));
printf("Average of 5, 10, 15 = %f\n", average(3, 5, 10, 15));
return 0;
}
Результат:
Average of 2, 3, 4, 5 = 3.500000
Average of 5, 10, 15 = 10.000000
Первый аргумент — количество последующих переменных аргументов. Только эллипсис (...) позволяет передавать переменное их число.
Важные замечания
- Тип каждого извлекаемого аргумента должен точно совпадать с ожидаемым в
va_arg— несоответствие — UB (неопределённое поведение). - Нет способа узнать количество аргументов автоматически — его нужно передавать явно (как
numвыше) или использовать специальный маркер (например,-1в конце). va_listможет быть передан в другие функции, но послеva_endон недействителен.- Для
printf-подобных функций используйтеvprintf,vsnprintfи семействоva_copy(C99).
Язык C
- Четыре проверенных паттерна пользовательских функций в C
- Классы хранения в C: область видимости, время жизни и производительность
- Как передавать одномерные и двумерные массивы в функции в C — практическое руководство
- Аргументы функций в Python: позиционные, именованные и параметры по умолчанию
- Переменные и типы данных в C++: подробное руководство по int, double, char, string, bool
- Переменные, типы данных и константы в C — практическое руководство
- Понимание назначений в Verilog: типы, синтаксис и лучшие практики
- Переменные в C: объявление, определение, инициализация, область видимости и классы хранения
- Функции в C: объявление, определение, вызов, аргументы (по значению и по ссылке), рекурсия
- Указатели в C: полное руководство — объявление, арифметика, массивы, функции и динамическая память