C言語の関数の可変長引数の使い方
- 作成日: 2024-03-28
- 更新日: 2024-03-28
- カテゴリ: C言語
C言語で関数の可変長引数を扱う方法を解説します。
C言語や他の言語を扱うYoutubeも公開しています。
興味がある方は以下のリンクからご覧ください。
関連動画
C言語で関数の可変長引数を扱う【stdarg.h, va_list, va_start, va_end, va_arg】 - YouTube
stdarg.h
C言語で可変長引数を使う場合はstdarg.h
をインクルードします。
#include <stdarg.h>
print関数を実装する
printf
関数のクローンであるprint
関数を実装します。
void print(const char *fmt, ...) {
va_list ap; // apを作成
va_start(ap, fmt); // apを初期化
vfprintf(stdout, fmt, ap); // apを出力
va_end(ap); // apを破棄
}
上記の関数は以下のように使うことができます。
print("Hello %d %s\n", 123, "Bye"); // Hello 123 Bye
まず可変長引数ですが、これは関数では...
というキーワードがこれに当たります。
void print(const char *fmt, ...);
上記の引数fmt
の後の...
が可変長引数です。
この引数には複数の引数を渡すことができます。
関数内ではまず最初にva_list
でap
を作成します。
va_list ap; // apを作成
このap
は可変長引数が入っているオブジェクトです。
可変長引数を処理したい時はこのap
を関数やマクロに渡します。
次にap
を初期化します。
va_start(ap, fmt); // apを初期化
上記ではva_start
マクロ関数でap
を初期化しています。
va_start
マクロ関数の第2引数には、...
の1つ前の引数を渡します。
print
関数の...
の1つ前の引数はfmt
ですから、これを渡すことになります。
vfprintf(stdout, fmt, ap); // apを出力
上記ではvfprintf
関数でap
を出力しています。
この関数は書式に従ってap
を出力してくれます。
第1引数には出力先のストリームを指定します。
va_end(ap); // apを破棄
上記では使い終わったap
を破棄しています。
sum関数を実装する
int sum(int n, ...) {
va_list ap;
va_start(ap, n);
int ret = 0;
for (int i = 0; i < n; i++) {
int k = va_arg(ap, int);
ret += k;
}
va_end(ap);
return ret;
}
上記のsum
関数は可変長引数のint
型の値を合計してその合計値を返すというものです。
第1引数には可変長引数の数を渡します。
printf("%d\n", sum(3, 10, 20, 30)); // 60
上記はsum
関数を使っているところです。
上記の場合、sum
関数は60
を返します。
for (int i = 0; i < n; i++) {
int k = va_arg(ap, int);
ret += k;
}
上記はap
からva_arg
マクロ関数で引数を取り出しているところです。
va_arg
には第1引数にap
を渡し、第2引数に引数の型を渡します。
引数がdouble
の場合はva_arg
の第2引数にはdouble
を渡します。
ret
には引数の合計値を加算しています。
関数の最後でret
を返しています。
puts_args関数を実装する
void puts_args(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
for (const char *p = fmt; *p; p++) {
switch (*p) {
case 'i': {
int n = va_arg(ap, int);
printf("%d ", n);
} break;
case 'f': {
double n = va_arg(ap, double);
printf("%f ", n);
} break;
case 's': {
const char *s = va_arg(ap, const char*);
printf("%s ", s);
} break;
}
}
printf("\n");
va_end(ap);
}
上記の関数は可変長引数をfmt
に従って出力する関数です。
第1引数にはfmt
の文字列を指定し、第2引数以降に可変長引数を渡します。
puts_args("ifs", 123, 3.14, "Hello");
// 123 3.14 Hello
上記はputs_args
関数を使っているところです。
for (const char *p = fmt; *p; p++) {
...
}
上記ではfmt
をポインタ変数p
に入れてループを回してp
をインクリメントしています。
switch (*p) {
case 'i': {
int n = va_arg(ap, int);
printf("%d ", n);
} break;
case 'f': {
double n = va_arg(ap, double);
printf("%f ", n);
} break;
case 's': {
const char *s = va_arg(ap, const char*);
printf("%s ", s);
} break;
}
上記では*p
の値に応じて、va_arg
でap
から引き出す引数の型を変えています。
*p
がi
だったらint
で引き出し、f
だったらdouble
で引き出し、s
だったらconst char *
で引き出します。
おわりに
今回はC言語の可変長引数を解説しました。
何か参考になれば幸いです。