Практические примеры
Функция регистрации
«Практические примеры» — бесплатный урок C Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C Academy содержит 4 уроков всего.
Функция ведения журнала
Средство ведения журнала — идеальный пример практического применения переменного количества аргументов. Мы хотим вызывать log_msg("user %s scored %d", name, score) так же, как printf.
В этом уроке Вы создадите небольшое полезное средство ведения журнала.
#include <stdio.h>
#include <stdarg.h>
void log_msg(const char *fmt, ...) {
va_list a; va_start(a, fmt);
vprintf(fmt, a);
va_end(a);
printf("\n");
}
int main(void) {
log_msg("user %s scored %d", "Ann", 90);
return 0;
}Добавление уровня важности
Настоящие средства ведения журнала помечают сообщения уровнем, например INFO или ERROR. Добавьте перед строкой формата фиксированный параметр для уровня.
#include <stdio.h>
#include <stdarg.h>
void logf(const char *level, const char *fmt, ...) {
printf("[%s] ", level);
va_list a; va_start(a, fmt);
vprintf(fmt, a);
va_end(a);
printf("\n");
}
int main(void) {
logf("INFO", "started with %d workers", 4);
return 0;
}Добавление временной отметки к сообщениям
Перед передачей формата можно дополнить каждую строку дополнительным контекстом. Здесь мы добавим в начало искусственный счётчик вместо временной отметки.
#include <stdio.h>
#include <stdarg.h>
static int line_no = 0;
void logf(const char *fmt, ...) {
printf("#%d ", ++line_no);
va_list a; va_start(a, fmt);
vprintf(fmt, a);
va_end(a);
printf("\n");
}
int main(void) {
logf("first %s", "event");
logf("value %d", 7);
return 0;
}Запись в stderr
Ошибки и диагностические сообщения обычно направляются в stderr. Используйте vfprintf(stderr, fmt, args), чтобы вывод журнала не смешивался с обычным выводом программы.
#include <stdio.h>
#include <stdarg.h>
void err(const char *fmt, ...) {
fprintf(stderr, "ERROR: ");
va_list a; va_start(a, fmt);
vfprintf(stderr, fmt, a);
va_end(a);
fprintf(stderr, "\n");
}
int main(void) {
err("failed to open %s", "data.txt");
return 0;
}Условное ведение журнала
Порог подробности позволяет отключать сообщения с низким приоритетом. Перед выводом сравнивайте уровень сообщения с настроенным минимальным уровнем.
#include <stdio.h>
#include <stdarg.h>
static int min_level = 2;
void logf(int level, const char *fmt, ...) {
if (level < min_level) return;
va_list a; va_start(a, fmt);
vprintf(fmt, a);
va_end(a);
printf("\n");
}
int main(void) {
logf(1, "debug hidden");
logf(3, "important %d", 42);
return 0;
}Создание строки сообщения
Иногда отформатированный текст нужно получить в буфере, а не вывести. Используйте vsnprintf, чтобы сформировать его, а затем решите, что с ним делать.
#include <stdio.h>
#include <stdarg.h>
void capture(const char *fmt, ...) {
char buf[128];
va_list a; va_start(a, fmt);
vsnprintf(buf, sizeof(buf), fmt, a);
va_end(a);
printf("captured: %s\n", buf);
}
int main(void) {
capture("id=%d name=%s", 5, "box");
return 0;
}Функция max с переменным количеством аргументов
Переменное количество аргументов подходит и для математических вспомогательных функций. Вот функция, которая возвращает наибольшее из нескольких целых чисел, используя параметр с количеством.
#include <stdio.h>
#include <stdarg.h>
int max_of(int count, ...) {
va_list a; va_start(a, count);
int best = va_arg(a, int);
for (int i = 1; i < count; i++) {
int v = va_arg(a, int);
if (v > best) best = v;
}
va_end(a);
return best;
}
int main(void) {
printf("%d\n", max_of(4, 3, 9, 2, 7));
return 0;
}Объединение строк
С помощью маркера NULL можно объединить любое количество строк в один буфер.
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
void join(char *out, const char *first, ...) {
out[0] = '\0';
va_list a; va_start(a, first);
const char *s = first;
while (s) { strcat(out, s); s = va_arg(a, const char *); }
va_end(a);
}
int main(void) {
char buf[64];
join(buf, "a", "b", "c", (char *)NULL);
printf("%s\n", buf);
return 0;
}Подсчёт целых аргументов переменного количества
Счётчик на основе маркера показывает, насколько гибок этот шаблон. Мы считаем значения, пока не встретим завершающее 0.
#include <stdio.h>
#include <stdarg.h>
int count_until_zero(int first, ...) {
va_list a; va_start(a, first);
int n = 0, v = first;
while (v != 0) { n++; v = va_arg(a, int); }
va_end(a);
return n;
}
int main(void) {
printf("%d\n", count_until_zero(5, 6, 7, 0));
return 0;
}Оформление в виде макроса
Распространённый приём — макрос, который автоматически подставляет уровень, чтобы вызывающему коду требовалось меньше записей. Макрос передаёт вызов настоящей функции с переменным количеством аргументов.
#include <stdio.h>
#include <stdarg.h>
void real_log(const char *lvl, const char *fmt, ...) {
printf("[%s] ", lvl);
va_list a; va_start(a, fmt);
vprintf(fmt, a);
va_end(a);
printf("\n");
}
#define LOG_INFO(...) real_log("INFO", __VA_ARGS__)
int main(void) {
LOG_INFO("ready in %d ms", 50);
return 0;
}Использование средства ведения журнала
Вот полноценное небольшое средство ведения журнала, объединяющее уровень и счётчик временных отметок и готовое для добавления в программу.
#include <stdio.h>
#include <stdarg.h>
static int seq = 0;
void mylog(const char *lvl, const char *fmt, ...) {
printf("%04d [%s] ", ++seq, lvl);
va_list a; va_start(a, fmt);
vprintf(fmt, a);
va_end(a);
printf("\n");
}
int main(void) {
mylog("INFO", "boot ok");
mylog("WARN", "low memory: %d MB", 64);
return 0;
}Быстрая проверка
Проверьте, насколько хорошо Вы поняли проектирование ведения журнала с переменным количеством аргументов.
Итоги
Вы создали практические инструменты для работы с переменным количеством аргументов:
- Средство ведения журнала, передающее свой формат в
vprintf/vfprintf. - Добавили уровни, счётчики, вывод в stderr и условную фильтрацию.
- Использовали
vsnprintf, чтобы сохранять сообщения в буферах. - Познакомились со вспомогательными функциями на основе маркеров и удобной обёрткой-макросом.
Часто задаваемые вопросы
Урок «Практические примеры» бесплатный?
Да — полный текст урока «Практические примеры» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C Academy, подпишись на CoddyKit PRO. Курс C Academy содержит 4 уроков всего.
Чему я научусь в уроке «Практические примеры»?
Функция регистрации Ты практикуешь C Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать C Academy?
Предыдущий опыт не требуется. C Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Практические примеры»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке C Academy?
Да. Каждый урок C Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Макросы stdarg
- Написание функций, подобных printf
- Проблемы безопасности типов
- Практические примеры