0Pricing
C Academy · レッスン

stdarg マクロ

va_list、va_start、va_arg です。

「stdarg マクロ」はCoddyKit上の無料C Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これは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;
}

省略記号

可変長引数関数は、最後のパラメーターとして ...(省略記号)を指定して宣言します。

可変部分がどこから始まるのかを関数が把握できるように、その前に少なくとも 1 つの名前付きパラメーターが必要です。

#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) は次の引数を返し、リストを進めます。読み取る正確な型を指定する必要があります。

呼び出すたびに、次の引数へ 1 つ進みます。

#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 になります。

そのため、va_arg では小さい整数を常に int として、浮動小数点数を double として読み取ってください。

#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 をコピーする

引数を2回走査する必要がある場合は、読み取る前に 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 マクロについての理解度を確認しましょう。

まとめ

可変個引数の仕組みについて学びました。

  • 名前付きパラメーターを少なくとも1つ置いた後に ... を付けて宣言します。
  • va_start(list, last) で開始し、va_arg(list, type) で読み取り、va_end(list) で後処理を行います。
  • マクロは個数を把握していないため、個数のパラメーターまたは番兵を使います。
  • デフォルト引数昇格に注意してください。小さい整数は int として、float は double として読み取ります。

よくある質問

「stdarg マクロ」レッスンは無料ですか?

はい。「stdarg マクロ」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C Academyコースには全4レッスンが含まれています。

「stdarg マクロ」で何を学びますか?

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

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

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

「stdarg マクロ」レッスンにはどのくらい時間がかかりますか?

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

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

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

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

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