stdarg.hは可変長引数を扱う際に使用するヘッダーです[1]。可変長引数とは、関数に渡す引数の数を実行時に変更できる仕組みのことです。この機能は以下のようなケースで役立ちます。

  1. printf関数のような可変長引数を取る関数の実装
    printfは可変長引数を取り、フォーマット文字列に応じて任意の数の引数を出力します。
  2. ラッパー関数の実装
    既存の関数に処理を追加したり、引数を変更したりする際に使えます。
  3. グループ化された引数の渡し方
    複数の値をグループ化して1つの引数として渡せます。

使用例を見ていきましょう。

printf関数の簡易実装
#include <stdarg.h>
#include <stdio.h>

void my_printf(const char* format, ...) {
    va_list args;
    va_start(args, format);
    
    while (*format) {
        if (*format == '%') {
            format++;
            switch(*format) {
                case 'd':
                    printf("%d", va_arg(args, int));
                    break;
                ...
            }
        } else {
            putchar(*format);
        }
        format++;
    }
    
    va_end(args);
}

int main() {
    my_printf("Answer is %d\n", 42);
    return 0;
}
グループ化された引数の受け渡し
#include <stdarg.h>

typedef struct {
    int x;
    int y;
} Point;

Point make_point(int x, int y) {
    Point p = {x, y};
    return p;
}

Point make_point_var(int num, ...) {
    va_list args;
    va_start(args, num);
    Point p = {va_arg(args, int), va_arg(args, int)};
    va_end(args);
    return p;
}

int main() {
    Point p1 = make_point(1, 2);
    Point p2 = make_point_var(2, 3, 4);
    return 0;
}

可変長引数は型の安全性がなく、間違った使い方をするとセグメンテーション違反などの深刻なエラーにつながる可能性があるため、十分に注意が必要です。一方で、柔軟性が高く様々な場面で活用できるという利点もあります。

C23 規格案では、stdarg.h ヘッダーは可変長引数リストを扱うためのマクロを定義しています。可変長引数リストとは、関数が呼び出された時に、引数の個数や型が未確定である引数リストのことです[2]

ヘッダーの内容

編集
  • __STDC_VERSION_STDARG_H__: このマクロは整数定数式であり、C23 規格に対応していることを示すために 202311L という値を持ちます。
  • va_list: 可変長引数リストの情報を持つオブジェクト型です。va_start, va_arg, va_end, va_copy マクロはこの型を利用します。
  • マクロ群: 以下の5つのマクロが定義されており、可変長引数リストを操作します。
    • va_start(va_list ap, ...): 可変長引数リスト ap を初期化します。... 以降の引数は無視されますが、互換性のため残されています。
    • va_arg(va_list ap, type): 次の引数の値を type 型に変換して返します。apva_startva_copy で初期化されている必要があります。
    • va_copy(va_list dest, va_list src): destsrc のコピーに初期化します。
    • va_end(va_list ap): 可変長引数リストの利用を終了し、リソースを解放します。

注意点

編集
  • va_startva_end は対応する形で呼び出す必要があります。
  • va_arg で取得する引数の型は、ポインタ型に変換できる型である必要があります。
  • 可変長引数リストは安全に使用するために注意が必要です。たとえば、存在しない引数を取得しようとするとプログラムがクラッシュするおそれがあります。

C23 規格案の変更点

編集

C23 規格案では、C++ との互換性を向上させるために、va_copy マクロの挙動が少し変更になりました。また、va_start マクロに渡す引数についても、互換性のため残されてはいますが、推奨されません。

まとめ

編集

stdarg.h ヘッダーは可変長引数リストを扱うための強力なツールですが、安全に使用するためには注意が必要です。C23 規格案では、C++ との互換性向上が図られていますが、推奨されない用法もあるので、最新の規格を確認しながら利用するようにしましょう。

脚註

編集
  1. ^ N2596 working draft — December 11, 2020 ISO/IEC 9899:202x (E). ISO/IEC JTC1/SC22/WG14. p. 246, §7.16 Variable arguments <stdarg.h>. http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2596.pdf. 
  2. ^ N3096 working draft — April 1, 2023 ISO/IEC 9899:2023 (E). ISO/IEC JTC1/SC22/WG14. p. 288, §7.16 Variable arguments <stdarg.h>. http://www.open-std.org/jtc1/sc22/wg14/www/docs/n3096.pdf. 

参考文献

編集