2012-02-16 10 views
11

コンソールにもログファイルにもログを記録しようとする機能がありますが、機能しません。可変長引き数を2回使用すると、コンソールにガベージが書き込まれます。何か案は?可変引数の引数を繰り返し使用しても機能しません

私はこの方法は、より理にかなっていると思います
void logPrintf(const char *fmt, ...) { 
     va_list ap; // log to logfile 
     va_start(ap, fmt); 
     logOpen; 
     vfprintf(flog, fmt, ap); 
     logClose; 
     va_end(ap); 
     va_list ap2; // log to console 
     va_start(ap2, fmt); 
     printf(fmt, ap2); 
     va_end(ap2); 
    } 
+1

printfではなく、2回目にvprintfを使用する必要があります。 –

答えて

-2

void logPrintf(const char *fmt, ...) { 
     va_list ap; // log to logfile 
     va_start(ap, fmt); 
     logOpen; 
     vfprintf(flog, fmt, ap); //logfile 
     printf(fmt, ap); //console 
     logClose; 
     va_end(ap); 
    } 
+0

トニーに感謝しますが、それはうまくいきません。ポインタがリストの最後に残っているので、2回目の使用でゴミが出ます。 – Neddie

+0

うん、それはまさに何が起こっているのですか。 'va_list'は常に参照渡しです。 –

+1

この例題( 'printf'の代わりに' vprintf'を使っていても)はmanページによれば間違っています: "apがva_arg(ap、type)を使用する関数に渡された場合、apの値はその機能。 " Linux x86-32では意図したとおりに動作しますが、例えば動作しません。 x86-64で。 –

2

はあなたのコンパイラをアップグレードし、それはより多くのC++のようなものです:

template <typename... Args> 
void logPrintf(const char *fmt, Args&&... args) { 
    logOpen; 
    fprintf(flog, fmt, args...); 
    logClose; 

    printf(fmt, args...); 
} 

もちろん、その後、提供するために、良い味だろうけどタイプセーフなバージョンprintffprintfです。

+0

上記の例ではC++ 11が必要です。 –

+1

@DavidGiven:yes(したがって*あなたのコンパイラをアップグレードする*)。 –

+0

私はvfprintfがここでfprintfである必要があると思います - あなたはva_listではなく実際の引数を渡しています。 –

8

​​を使用する必要がある場合は、printf()を使用しようとするため、元のコードが失敗します。 (おそらく彼らはflogファイルストリームを閉じて、オープンとマクロだ、表記法を与えられた)額面でlogOpenlogClose文のような怪しげなポイントを取ると、コードは次のようになります。

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;もう一度va_start()を使用する前に、va_end()を使用している限り、同じものを2回使用しても問題ありません。va_list値が別の関数(このコードでvfprintf()と​​)に渡され

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_end()を呼び出すだけで安全です。

このコードではva_copy()の必要はありません。それは動作しますが、それは必要ありません。このコードでは、args1va_end()を呼び出すために、呼び出し元のコードの責任であることを

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_listに合格し、あなたが二度リストを処理する必要がありますされている場合など、他の状況でva_copy()を必要としています。確かに、標準は言う:

va_startva_copyマクロ の各呼び出しは同じ関数内va_endマクロの対応する呼び出しによってマッチされなければなりません。

logVprintf()機能がargs1を初期化するためにva_startまたはva_copyのいずれかを呼び出すことはありませんので、それは合法的args1va_endを呼び出すことはできません。一方、標準ではargs2に対してva_endを呼び出す必要があります。

logPrintf()機能は現在logVprintf()の観点で実施することができる。

void logPrintf(const char *fmt, ...) 
{ 
    va_list args; 
    va_start(args, fmt); 
    logVprintf(fmt, args); 
    va_end(args); 
} 

この構造 - va_listと省略記号(変数引数)を取り、カバー機能を取得し、動作に渡す操作機能機能をva_listに変換した後で作業するのが良い方法です。遅かれ早かれ、通常、va_list引数を持つバージョンが必要です。

+2

これは、アーキテクチャの変更を推奨することなくOPの質問を直接解決する正解です。 – Vortico

関連する問題