C言語で可変長引数を取る関数を定義する
可変長引数とは、printf関数が取るような、あらかじめ個数が決まっていない形式の引数のことである。
例えば、自分用のprintfを新たに定義したいとすると、引数の部分は次のように書く。
void myprintf(char *fmt, ...) {
}
こう書くと、fmtに続く引数が可変になる。
...の前には引数が複数あってもよいが、...の後に引数があってはならない。
つまり、...は引数の最後でなければならない。
渡された可変長引数を使うには、stdarg.hで定義されている型やマクロを使う。以下にそれらの使い方の例を示す。
#include <stdio.h> #include <stdarg.h> void myprintf(char *fmt, ...) { va_list ap; va_start(ap, fmt); char *p = fmt; while (*p) { if (*p == 'd') { printf("%d ", va_arg(ap, int)); p++; continue; } if (*p == 'c') { printf("%c ", va_arg(ap, char)); p++; continue; } fprintf(stderr, "不正な文字\n"); exit(1); } printf("\n"); }
va_list型は引数のリストをイテレートするためのポインタを表す。
"va"はおそらく可変超引数を表す英語variadic argumentsの略。
va_start(ap, fmt)によって、apがfmtに続く引数のリストの先頭を指している状態になる。
一般にva_startの第二引数には...の直前の引数の識別子を指定する。
引数のリストを順番に調べるには、va_argマクロを使う。va_arg(ap, int)はapが指している位置の引数をint型として返し、apが指す位置を一つ先に進める。
myprintf関数は簡易的なprintfを実現する。具体的には、dとcからなる文字列と可変長引数を受け取り、可変長引数を参照しながら、dを整数に、cを文字に置き換える。
例えばmyprintf("dcdcd", 1, 'a', 2, 'b', 3)を呼び出すと1 a 2 b 3と表示される。