printf()元のコードは、使用する必要がある場所で使用しようとするため、失敗しますvprintf()。logOpenandステートメントのような疑わしい点logCloseを額面通りに取ると (表記を考えると、おそらくそれらはflogファイル ストリームを開いたり閉じたりするマクロです)、コードは次のようになります。
void logPrintf(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
logOpen;
vfprintf(flog, fmt, ap);
logClose;
va_end(ap);
va_list ap2;
va_start(ap2, fmt);
vprintf(fmt, ap2);
va_end(ap2);
}
2 つの個別のva_list変数を使用する必要は特にありません。もう一度使用する前に、同じものを2回使用しても問題ありません。va_end()va_start()
void logPrintf(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
logOpen;
vfprintf(flog, fmt, ap);
logClose;
va_end(ap);
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
}
va_list値が別の関数 (vfprintf()およびこのコード) に渡されるvprintf()と、現在の関数では使用できなくなったと想定する必要があります。それを呼び出すだけで安全va_end()です。
va_copy()このコードでは は必要ありません。動作しますが、必要ありません。関数が渡され、リストを2回処理する必要がva_copy()ある場合など、他の状況で必要になります。va_list
void logVprintf(const char *fmt, va_list args1)
{
va_list args2;
va_copy(args2, args1);
logOpen;
vfprintf(flog, fmt, args1);
logClose;
vprintf(fmt, args2);
va_end(args2);
}
このコードでは、va_end()onを呼び出すのは呼び出し元のコードの責任であることに注意してくださいargs1。実際、標準は次のように述べています。
va_startおよびマクロの各呼び出しは、同じ関数内va_copyのマクロの対応する呼び出しと一致する必要があります。va_end
logVprintf()関数はva_startorのどちらも呼び出さないため、va_copyinitializeargs1を正当va_endに呼び出すことはできませんargs1。一方、標準では、 を呼び出す必要がありva_endますargs2。
関数は今logPrintf()の観点から実装できます。logVprintf()
void logPrintf(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
logVprintf(fmt, args);
va_end(args);
}
この構造 — a を受け取る操作関数va_listと、省略記号 (可変引数) を取り、それらを a への変換後に操作関数に渡すカバー関数va_list— は、多くの場合、うまく機能します。遅かれ早かれ、通常はva_list引数付きのバージョンが必要になります。