可変個引数 (C++をもう一度)
[履歴] (2014/12/22 07:04:03)
最近の投稿
注目の記事

サンプルコード

#include <iostream>
#include <cstdarg>
#include <cstdio> // vprintf, vsprintf
using namespace std;

void MyFunc(int first, ...) {
    va_list args; // 入れ物を確保
    va_start(args, first); // 入れ物の中身を引数で初期化
                           // 直前の引数 first を知らせる必要有

    // 好きな型の値として引数を shift 取り出し
    // - int 以下の型 (short, char, bool) は int に変換済
    // - double 以下の型 (float) は double に変換済
    // cout << va_arg(args, char) << endl; // char と指定するとエラー
    cout << va_arg(args, int) << endl; //=> 97
    cout << (char)(va_arg(args, int)) << endl; //=> b
    cout << (char)(va_arg(args, int)) << endl; //=> c

    va_end(args); // 終了処理
}

void MyFuncPtr(int dummy, ...) {
    va_list args;
    va_start(args, dummy);
    cout << va_arg(args, char*) << endl;
    const void* vp = va_arg(args, const void*);
    const void* vp_ = va_arg(args, const void*);
    va_end(args);
}

void MyPrintF(const char* format, ...) {
    va_list args;
    va_start(args, format);

    // printf と動作は同じ
    vprintf(format, args); 

    // sprintf と動作は同じ
    char str[128];
    vsprintf(str, format, args);
    cout << str << flush;

    va_end(args);
}

int main() {
    // 可変個引数
    // - 最初の引数は特別扱い可能
    // - 引数の型や個数を関数内で取得できない
    // - int 系列引数に double 系列を渡すとエラーは出ずに不具合 (キャストされないため)
    // - double 系列引数に int 系列を渡すとエラーは出ずに不具合 (キャストされないため)
    MyFunc('Z', 'a', 'b', 'c');
    MyFunc('Z', 97.7, 98.8, 99.9); // 不具合。エラーはなく変な出力
    MyFunc('Z', (int)97.7, (int)98.8, (int)99.9); // 自分でキャストすれば一応は回避できる

    // ポインタを渡す場合
    // - 変換は一切行われない (short*, char*, bool*, float* であってもそのまま)
    // - 必要に応じて自分で変換して渡しましょう
    // - NULLポインタは 0 で定義される環境があり int 型と混同され得るため
    //   何らかのポインタ型に自分で変換して渡しましょう
    char str[] = "string";
    MyFuncPtr('Z', str,
              static_cast<const void*>(str),
              static_cast<const void*>(NULL));

    // 可変個引数の関数内で printf や sprintf を実行したい場合
    int n = 1;
    MyPrintF("%d + %d = %d\n", n, n, n+n);

    return 0;
}
関連ページ