Page 26 stdarg

stdarg、標準引数とでもいいましょうか。知っておくとちょっと便利な機能です。

printfの定義は、

int printf(const char *format, ...);

となっていますが、このような、一番最後の「...」を表現するのにstdargを使用します。

va_start / va_arg / va_end

とりあえず、「...」を引数とした関数を作ってみましょう。

int function(const char *text, ...){
	/* 処理省略 */
	return 0;
}

とりあえず、できました。呼び出す方は、function("a","b","c","d")など、適当に引数を並べることができます。問題は、function内部で、いかに引数を取り出すか、です。

最初の引数は*textなので、取り出せます。

2番目以降の引数、つまり「...」の部分は、va_startによって、va_list型の値として取り出せます。

void va_start(va_list ap, argN);

argNには「...」の前の引数、この場合では、「text」をセットします。

#include <stdarg.h>
/* その他省略 */

/* main関数省略 */

int function(const char *text, ...){
	va_list ap; /* va_list型変数 */
	va_start(ap, text);
	/* 処理省略 */
	return 0;
}

va_listから適当な型で引き出すにはva_argを使用します。

type va_arg(va_list ap, type);
#include <stdarg.h>
/* その他省略 */

/* main関数省略 */

int function(const char *text, ...){
	const char* text2;
	va_list ap; /* va_list型変数 */
	va_start(ap, text);
	text2 = va_arg(ap, const char*);
	/* 処理省略 */
	return 0;
}

va_listをクローズするのは、va_endです。

void va_end(va_list ap);
#include <stdarg.h>
#include <stdio.h>
/* その他省略 */

/* main関数省略 */

int function(const char *text, ...){
	const char* text2;
	va_list ap; /* va_list型変数 */
	va_start(ap, text);
	text2 = va_arg(ap, const char*);
	va_end(ap);
	printf("%s, %s\n", text, text2);
	return 0;
}

function("abc","def")で呼び出してみると、

abc, def

と、表示してくれます。

stdargとstdio

va_listから適当な型の変数を取り出して表示する例をやりましたが、stdio.hに定義されている、vprintfなどを使えば、va_list型をそのまま使って入出力することができます。

int vfprintf(FILE *stream, const char *format, va_list ap);
int vprintf(const char *format, va_list ap);
int vsnprintf(char *s, size_t n, const char *format, va_list ap);
int vsprintf(char *s, const char *format, va_list ap);

内容は、fprintf、printf、snprintf、sprintfと同じで、va_listを使うところが異なっています。↓のようにすれば、printfとほぼ変わらない関数になります。画面出力にプラスアルファしたいときに使えます。

#include <stdarg.h>
#include <stdio.h>
/* その他省略 */

/* main関数省略 */

/* 「printf」とほぼ同じ関数 */
int function(const char *text, ...){
	va_list ap; /* va_list型変数 */
	va_start(ap, text);
	vprintf(text, ap);
	va_end(ap);
	return 0;
}

また、vsprintfなどを使えば、フォーマット済み文字列を作成できるので、関数呼び出し元でフォーマット済み文字列を作成する必要がなく、関数内でフォーマットし、別の文字列引数の関数に渡すということもできます。

戻る