名 前
stdarg, va_start, va_arg, va_end, va_copy − 個 数 、 型 が 可 変 な 引 数 リ ス ト
書 式
#include <stdarg.h>
void
va_start(va_list ap, last);
type va_arg(va_list ap,
type);
void va_end(va_list ap);
void va_copy(va_list dest, va_list
src);
説 明
関 数 は 呼 び 出 し に 際 し て 、 個 数 や 型 が 可 変 な 引 数 を と る こ と が で き る 。 イ ン ク ル ー ド フ ァ イ ル <stdarg.h> で は va_list 型 が 宣 言 さ れ て お り 、 3 つ の マ ク ロ が 定 義 さ れ て い る 。 こ れ ら を 用 い る と 、 呼 び 出 さ れ た 関 数 側 で は 個 数 や 型 を 知 ら な い 引 き 数 の リ ス ト を 、 順 に 一 つ づ つ 読 み 込 む こ と が で き る 。 呼 び 出 さ れ る 関 数 で は 、 va_list 型 の オ ブ ジ ェ ク ト が 宣 言 さ れ て い な け れ ば な ら な い 。 こ の オ ブ ジ ェ ク ト が va_start(), va_arg(), va_end() の 各 マ ク ロ に よ っ て 扱 わ れ る 。
va_start()
va_start() マ ク ロ は 最
初 に 呼 び 出 さ
な け れ ば な ら
な い 。 こ れ は
ap を 初 期 化 し
、 va_arg() と va_end() で
用 い る こ と が
で き る よ う に
す る 。 引 き 数
last は 引 き 数 リ
ス ト の う ち 、
可 変 な 部 分 の
直 前 に 置 か れ
る 引 き 数 の 名
前 で あ る 。 つ
ま り 呼 び 出 さ
れ た 関 数 が 型
を 知 っ て い る
最 後 の 引 き 数
で あ る 。 こ の
引 き 数 は レ ジ
ス タ ー 変 数 や
関 数 、 配 列 と
し て 宣 言 し て
は な ら な い 。
こ の 引 き 数 の
ア ド レ ス が
va_start() マ ク ロ で
用 い ら れ る か
も し れ な い か
ら で あ る 。
va_arg()
va_arg() マ ク ロ は 、
呼 び 出 し 時 に
指 定 さ れ た 引
き 数 の う ち 、
次 の 位 置 に あ
る も の を 指 定
し た 型 type の 値
と し て 取 得 す
る 。 引 き 数 ap
は va_list ap で 、
va_start() に よ っ て
初 期 化 さ れ て
い る 必 要 が あ
る 。 va_arg() を 呼 び
出 す ご と に ap
は 変 更 さ れ 、
次 回 の 呼 び 出
し の 際 に 、 さ
ら に 次 の 引 き
数 を 返 す よ う
に な る 。 引 き
数 type は 型 の 名
前 で あ る 。 type
の 前 に * を 付 け
れ ば 、 オ ブ ジ
ェ ク ト へ の 型
付 き ポ イ ン タ
ー が 得 ら れ る
。
va_start() マ ク ロ の 直 後 に va_arg() を 最 初 に 実 行 す る と 、 last の 次 の 引 き 数 が 返 る 。 続 け て 実 行 す る と 、 残 り の 引 き 数 が そ れ ぞ れ 返 る 。 次 の 引 き 数 が な か っ た り 、 type が 次 の 引 き 数 の 実 際 の 型 と 互 換 で な い 場 合 (デ フ ォ ル ト の 引 き 数 変 換 で 扱 え な か っ た 場 合 ) に は 、 予 測 で き な い エ ラ ー が 起 こ る 。
ap が va_arg(ap,type) の 形 で 関 数 に 渡 さ れ る と 、 ap の 値 は 関 数 か ら 返 っ て 来 た 後 は 不 定 と な る 。
va_end()
va_start() が 実 行 さ れ
る 毎 に 、 同 じ
関 数 内 で 対 応
す る va_end() が 実 行
さ れ な け れ ば
な ら な い 。
va_end(ap) が 呼 び
出 さ れ た 後 、
変 数 ap の 値 は
不 定 と な る 。
va_start() と va_end() の 組
を 何 回 も 並 べ
て 使 う こ と も
可 能 で あ る 。
va_end() は マ ク ロ か
も し れ な い し
関 数 か も し れ
な い 。
va_copy()
va_copy() マ ク ロ は (初
期 化 済 み の ) 可
変 長 引 き 数 リ
ス ト src を dest に
コ ピ ー す る 。
動 作 は 、 last 引
き 数 に dest を 渡
し て va_start() を dest
に 適 用 し 、 そ
れ か ら src が 現
在 の 状 態 に 達
す る ま で に 呼
び 出 し た の と
同 じ 回 数 だ け
va_arg() を 呼 び 出 す
、 の と 同 じ こ
と を 行 う 。 す
ぐ 分 か る va_list の
実 装 は 、 variadic な
関 数 の ス タ ッ
ク フ レ ー ム の
ポ イ ン タ ー で
あ る 。 こ の よ
う な 場 合 (ほ と
ん ど は そ う で
あ る )、 単 に 以
下 の よ う に す
れ ば い い よ う
に 思 え る 。
va_list aq = ap; 残 念 な が ら 、 (長 さ 1の )ポ イ ン タ ー の 配 列 と し て 扱 う シ ス テ ム も あ る 。 そ の よ う な 場 合 、 以 下 の よ う に す る 必 要 が あ る 。
va_list aq;
*aq = *ap; 最 後 に 、 引
き 数 を レ ジ ス
タ ー で 渡 す シ
ス テ ム の 場 合
、 va_start() で メ モ
リ ー を 割 り 当
て 、 引 き 数 を
格 納 し 、 次 の
引 き 数 が ど れ
か を 指 し 示 す
よ う に す る 必
要 が あ る 。 そ
し て va_arg() で リ ス
ト を 順 番 に た
ど り 、 va_end() で 割
り 当 て た メ モ
リ ー を 開 放 す
る 。 こ の よ う
な 状 況 に 対 応
す る た め 、 C99 で
は va_copy() マ ク ロ
を 追 加 し 、 前
述 の よ う な 割
り 当 て は 以 下
の よ う に 置 き
換 え ら れ る よ
う に し た 。
va_list aq;
va_copy(aq, ap);
...
va_end(aq);
va_copy() が 実 行 さ れ る ご と に 、 対 応 す る va_end() を 同 じ 関 数 内 で 実 行 し な け れ ば な ら な い 。 こ の 名 前 は ま だ draft proposal な の で 、 va_copy() の 代 わ り に __va_copy を 用 い る シ ス テ ム も あ る 。
属 性
マ ル チ ス レ ッ デ ィ ン グ (pthreads(7) 参 照 ) マ ク ロ va_start(), va_arg(), va_end(), va_copy() は ス レ ッ ド セ ー フ で あ る 。
準 拠
va_start(), va_arg(), va_end() マ ク ロ は C89 準 拠 で あ る 。 va_copy() は C99 で 定 義 さ れ て い る 。
注 意
こ れ ら の マ ク ロ は 、 以 前 か ら 用 い ら れ て き た 同 等 の マ ク ロ 群 と 互 換 で は な い 。 過 去 の も の と 互 換 な バ ー ジ ョ ン は 、 イ ン ク ル ー ド フ ァ イ ル <varargs.h> に 存 在 す る 。 歴 史 的 な セ ッ ト ア ッ プ は 以 下 の と お り で あ る 。
#include <varargs.h>
void
foo(va_alist)
va_dcl
{
va_list ap;
va_start(ap);
while (...) {
...
x = va_arg(ap, type);
... }
va_end(ap); }
va_start マ ク ロ に '}' を 含 み 、 va_end マ ク ロ に 対 応 す る '{' を 含 む シ ス テ ム も あ る の で 、 こ の 二 つ の マ ク ロ は 同 じ 関 数 に な け れ ば な ら な い 。
バ グ
varargs マ ク ロ と は 異 な り 、 stdarg マ ク ロ で は 固 定 引 き 数 な し で 関 数 を 指 定 す る こ と が 許 さ れ て い な い 。 こ れ は varargs ベ ー ス の コ ー ド を stdarg の コ ー ド に 書 き 換 え る と き に 、 面 倒 な 作 業 の も と に な る 。 ま た 、 す べ て の 引 き 数 を va_list と し て 可 変 個 指 定 し た い よ う な 場 合 (vfprintf(3) な ど ) に も 障 害 と な る 。
例
関 数 foo は 書 式 文 字 か ら な る 文 字 列 を 受 け 入 れ 、 そ の 書 式 文 字 に 対 応 す る 型 で 可 変 個 の 引 き 数 を 読 み 込 み 、 印 字 す る 。
#include
<stdio.h>
#include <stdarg.h>
void
foo(char *fmt, ...)
{
va_list ap;
int d;
char c, *s;
va_start(ap,
fmt);
while (*fmt)
switch (*fmt++) {
case 's': /* string */
s = va_arg(ap, char *);
printf("string %s\n", s);
break;
case 'd': /* int */
d = va_arg(ap, int);
printf("int %d\n", d);
break;
case 'c': /* char */
/* need a cast here since va_arg only
takes fully promoted types */
c = (char) va_arg(ap, int);
printf("char %c\n", c);
break; }
va_end(ap); }
こ の 文 書 に つ い て
こ の man ペ ー ジ は Linux man−pages プ ロ ジ ェ ク ト の リ リ ー ス 3.79 の 一 部 で あ る 。 プ ロ ジ ェ ク ト の 説 明 と バ グ 報 告 に 関 す る 情 報 は http://www.kernel.org/doc/man−pages/ に 書 か れ て い る 。