Макросы stdarg
va_list, va_start, va_arg
«Макросы stdarg» — бесплатный урок C Academy на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C Academy содержит 4 уроков всего.
Что такое функции с переменным числом аргументов
Функция с переменным числом аргументов принимает переменное количество аргументов. Вы уже использовали такую функцию: printf может принимать любое количество значений.
В C можно создавать собственные функции с помощью макросов <stdarg.h>.
#include <stdio.h>
int main(void) {
printf("%d %d %d\n", 1, 2, 3);
printf("%s\n", "any count of args");
return 0;
}Многоточие
Функцию с переменным числом аргументов объявляют с помощью ... (многоточия) в качестве последнего параметра.
Перед ним должен находиться хотя бы один именованный параметр, чтобы функция знала, где начинается переменная часть.
#include <stdio.h>
#include <stdarg.h>
void demo(int count, ...) {
printf("This function takes %d extra args\n", count);
}
int main(void) {
demo(3, 10, 20, 30);
return 0;
}Подключение stdarg.h
Чтобы считывать переменные аргументы, необходимо добавить #include <stdarg.h>.
Этот заголовочный файл определяет тип va_list и макросы va_start, va_arg и va_end.
#include <stdio.h>
#include <stdarg.h>
void show(int n, ...) {
va_list args;
va_start(args, n);
va_end(args);
printf("set up and cleaned up\n");
}
int main(void) {
show(2, 5, 6);
return 0;
}va_list и va_start
Объявите переменную типа va_list для отслеживания текущей позиции. Затем вызовите va_start(list, last), передав последний именованный параметр.
Это указывает списку на первый переменный аргумент.
#include <stdio.h>
#include <stdarg.h>
void first(int count, ...) {
va_list args;
va_start(args, count);
int value = va_arg(args, int);
printf("first variadic arg = %d\n", value);
va_end(args);
}
int main(void) {
first(1, 99);
return 0;
}va_arg: чтение значений
va_arg(list, type) возвращает следующий аргумент и перемещает список вперёд. Необходимо указать точный тип для чтения.
Каждый вызов перемещает позицию на один аргумент вперёд.
#include <stdio.h>
#include <stdarg.h>
void three(int n, ...) {
va_list args;
va_start(args, n);
int a = va_arg(args, int);
int b = va_arg(args, int);
int c = va_arg(args, int);
printf("%d %d %d\n", a, b, c);
va_end(args);
}
int main(void) {
three(3, 7, 8, 9);
return 0;
}va_end: очистка
Всегда вызывайте va_end(list), когда закончите чтение. Эта функция выполняет необходимую платформе очистку.
Если забыть её вызвать, в некоторых системах это приведёт к неопределённому поведению.
#include <stdio.h>
#include <stdarg.h>
int add_two(int dummy, ...) {
va_list args;
va_start(args, dummy);
int sum = va_arg(args, int) + va_arg(args, int);
va_end(args);
return sum;
}
int main(void) {
printf("%d\n", add_two(0, 4, 6));
return 0;
}Определение количества аргументов
Макросы не могут определить, сколько аргументов было передано. Вы должны сообщить это самостоятельно.
Распространённый подход — передавать первым параметром количество, как в sum(3, a, b, c).
#include <stdio.h>
#include <stdarg.h>
int sum(int count, ...) {
va_list args;
va_start(args, count);
int total = 0;
for (int i = 0; i < count; i++)
total += va_arg(args, int);
va_end(args);
return total;
}
int main(void) {
printf("%d\n", sum(4, 1, 2, 3, 4));
return 0;
}Использование значения-маркера
Другой способ обозначить конец — использовать маркер: специальное завершающее значение, которое должен передать вызывающий код, например -1 или NULL.
Выполняйте цикл, пока не прочитаете маркер.
#include <stdio.h>
#include <stdarg.h>
int sum_until_neg(int first, ...) {
va_list args;
va_start(args, first);
int total = first, v;
while ((v = va_arg(args, int)) != -1)
total += v;
va_end(args);
return total;
}
int main(void) {
printf("%d\n", sum_until_neg(10, 20, 30, -1));
return 0;
}Продвижение аргументов по умолчанию
Аргументы переменного количества проходят продвижение по умолчанию: char и short преобразуются в int, а float — в double.
Поэтому всегда читайте малые целые числа как int, а числа с плавающей точкой — как double с помощью va_arg.
#include <stdio.h>
#include <stdarg.h>
void show_double(int n, ...) {
va_list args;
va_start(args, n);
double d = va_arg(args, double);
printf("%.2f\n", d);
va_end(args);
}
int main(void) {
show_double(1, 3.5f);
return 0;
}Копирование va_list
Если необходимо пройти по аргументам дважды, используйте va_copy(dest, src), чтобы скопировать список перед чтением.
После va_end нельзя повторно использовать va_list, не начав работу заново с помощью va_start.
#include <stdio.h>
#include <stdarg.h>
void twice(int n, ...) {
va_list a, b;
va_start(a, n);
va_copy(b, a);
printf("%d %d\n", va_arg(a, int), va_arg(b, int));
va_end(a);
va_end(b);
}
int main(void) {
twice(1, 42);
return 0;
}Вычисление среднего значения
Объединив шаблон с количеством аргументов и чтение чисел с плавающей точкой, можно вычислить среднее значение списка чисел, переданных в переменном количестве.
#include <stdio.h>
#include <stdarg.h>
double average(int count, ...) {
va_list args;
va_start(args, count);
double sum = 0;
for (int i = 0; i < count; i++)
sum += va_arg(args, double);
va_end(args);
return sum / count;
}
int main(void) {
printf("%.2f\n", average(3, 2.0, 4.0, 6.0));
return 0;
}Быстрая проверка
Проверьте, насколько хорошо Вы поняли макросы stdarg.
Итоги
Вы изучили механизм работы с переменным количеством аргументов:
- Объявляйте функцию с помощью
...после хотя бы одного именованного параметра. va_start(list, last)начинает работу,va_arg(list, type)читает аргумент, аva_end(list)выполняет очистку.- Макросы не знают количество аргументов — используйте параметр с количеством или маркер.
- Учитывайте продвижение по умолчанию: читайте малые целые числа как
int, а числа с плавающей точкой — какdouble.
Часто задаваемые вопросы
Урок «Макросы stdarg» бесплатный?
Да — полный текст урока «Макросы stdarg» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C Academy, подпишись на CoddyKit PRO. Курс C Academy содержит 4 уроков всего.
Чему я научусь в уроке «Макросы stdarg»?
va_list, va_start, va_arg Ты практикуешь C Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать C Academy?
Предыдущий опыт не требуется. C Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.
Сколько времени занимает урок «Макросы stdarg»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке C Academy?
Да. Каждый урок C Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.