0Pricing
C Academy · Урок

Практические примеры

Функция регистрации

«Практические примеры» — бесплатный урок 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 — локальная установка не требуется.

Все уроки этого курса

  1. Макросы stdarg
  2. Написание функций, подобных printf
  3. Проблемы безопасности типов
  4. Практические примеры
← Назад к C Academy