0Pricing
C Academy · レッスン

実践例

ロギング関数を作成します。

「実践例」はCoddyKit上の無料C Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これは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 番兵を使うと、任意個数の文字列を1つのバッファーに連結できます。

#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;
}

可変個引数の int を数える

番兵を使ったカウンターによって、このパターンの柔軟性が分かります。終端を示す 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時間対応のAIチューター)、C Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C Academyコースには全4レッスンが含まれています。

「実践例」で何を学びますか?

ロギング関数を作成します。 ブラウザで直接実行するハンズオンコードでC Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

C Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのC Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。

「実践例」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このC Academyレッスンでコードを書いて実行できますか?

はい。すべてのC Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. stdarg マクロ
  2. printf 風関数の記述
  3. 型安全性に関する注意点
  4. 実践例
← C Academyに戻る