可変長引数
通常、関数は引数の個数を決めて実装しています。
個数を決めずに関数を使いたいケースに対応するため、C言語では「可変長引数」が用意されています。
「可変長引数」は「stdarg.h」ヘッダを定義することにより実装が可能となります。
可変長引数の関数の形式は次の通りです。
型(int やchar*、voidなど) 関数名(データ型 変数名, ...)
※「...」はドットが3個並ぶ形式です。
|
また、可変長引数で使用される関数は次の通りとなります。
関数 | 処理 | void va_start(va_list args, <引数>) | 可変長個数の引数にアクセスする準備をします。 | <データ型>va_arg(va_list args, <データ型>) | <データ型>の引数を取得します。 | void va_end(va_list args) | 引数へのアクセスを終了します。 |
それではサンプルを見てください。
このサンプルでは次の3種類について説明しています。
数字のみのケース
文字列のみのケース
printfのような引数を書式指定子をイメージした感じで使用するケース
最初に数字のケースについて見てみます。
14行目で数字を使った可変長引数のテストをしています。
文頭にも述べましたとおり、29行目の関数の引数の後方が「...」となっています。
これが可変長引数の特徴となります。
14行目に戻ってください。
引数をみると「3, 1, 3, 5」となっています。 第1引数の「3」が可変長引数に使用する個数を表しています。 また、このケースでは引数の個数が3個(関数の引数として指定した2番目以降の「1, 3, 5」)とし、1番目のデータが「1」、2番目のデータが「3」、そして3番目のデータを「5」としています。
この引数の受け渡しを29行目の「...」で表してます。
32行目の「va_list」で宣言した変数の「args」でこれから使用する可変長変数であることを宣言しています。
35行目で文頭で説明したとおり可変長引数で実行する準備をしています。
39行目では第1引数のデータ個数を使ってfor文の繰り返し回数を指定しています。
また、41行目では「va_args」を使って引数の値を取得しています。
処理を終えたら45行目のように「va_end」を使って終了処理をしています。
次は文字列のケースです。
49行目を見てください。
文字列を渡す場合も第1引数で文字列の個数を指定しています。
あとは数字が文字列に変わっただけで、実行方法はほぼ変わりません。
ただし、文字列として実行しているため、60行目のように「va_arg」の引数を「char*」としています。
さいごに、printf関数のような書式指定子のような感じで第1引数を文字列で渡した場合を見てみます。
70行目を見ていただくと、第1引数が「char *変数」となっていることが確認できると思います。
引数の準備などで使用してる「va_list」、「va_start」および「va_end」は上記で説明した通りとなります。
ここでは可変長引数を取得するためにポイント演算を使用しています。
ポイント演算は下記のページにも記載していますので、よろしければ参考にしてください。
ポイント演算 [http://abc3.me/computer/c_2010/31/c_2010-1-1.php]を見てください。
書式指定子のイメージとして視野にいれたのは次の内容のみとなります。
※チェック機能は組み込んでいません。
種類 | 内容 | % | 書式指定子の「%」 (例)%s | \0 | 文字列の終端「¥(円マーク) + 0(ゼロ)」 | s | 文字 | d | 数字 | その他 | 空白など上記に一致しないケースは次の文字を参照させる |
ポインタ演算を使用しているので「++」を使い、次のデータを参照しています。
85行目を見ていただくと確認できると思いますが、文字列の終端である「\0」でない間、処理を継続しています。
90行目にあるexists変数は最初(1文字目)に「%」が存在する場合の対処として使っているフラグです。
書式指定子は「% + 識別文字」の形式をとっています。
この形式により「%」を見つけたらフラグ「flg」を立てています。
上記にも述べたとおり、これは簡易サンプルであるため、チェック機能は設けておりません。
実際に作成する場合は、printfで使われるべき書式指定子のケースを盛り込んだ実装にする必要があります。
サンプルプログラムを実行した結果です。
|
|