5

次の質問に対する答えを見つけることができず、機能に関連する問題がいくつかあります。

私の主なプログラミングは C# で行われており、勉強中に C++ を実際に学んだことはありませんが、現在の仕事では C++ プログラミングもいくつか行う必要があります。

C++ プログラミングのほとんどは元従業員によって行われ、彼はロギング用の関数を作成しました。

時々、この関数はエラー (アクセス違反) になります。これはユーザーには表示されませんが、デバッガーでコードを実行しているときに表示されます。

エラーが発生すると、次のコード行が示されます。

vfprintf( LogFile, fmt, va );

次に、前後のコードを詳しく調べました。上記をコンテキストに入れると、コードは次のようになります。

void FileLog( char *fmt, ... )
{
  va_list       va;
  struct  time  t;
  struct  date  d;
  long          clk;
  static int    ReEntrant = 0;

  if( FileLogEnabled == false )
    return;

  ReEntrant++;
  if( ReEntrant > 1 )
    return;

  if( LogFile == NULL )
    LogFile = fopen( LogFileName, "a+" );
  if( LogFile != NULL )
  {
    gettime( &t );
    getdate( &d );
    fprintf( LogFile, "\n%d-%02d-%02d %2d:%02d:%02d.%02d0> ", d.da_year, d.da_mon, d.da_day, t.ti_hour, t.ti_min, t.ti_sec, t.ti_hund );

    va_start( va, fmt );
    vfprintf( LogFile, fmt, va );
    va_end( va );

    fflush( LogFile );
    ...
  }
  ReEntrant = 0;
}

実際、なぜそれが必要なのか理解できません (必要な場合は?) fprintf と vfprintf の両方を呼び出しますか? 最初の fprintf 呼び出しは、フォーマットされた文字列をストリーム (ファイル) に書き込むと思いますが、それで十分でしょうか?

少しの説明またはいくつかの情報をいただければ幸いです:)

編集: nos からのコメントの後 - 今日このエラーを頻繁に引き起こしている関数への特定の呼び出しを追跡しました。

FileLog( "TimerRestore[%d], Name=%s", Package.CurGame->Timers[ Index ].Name.c_str() );

「TimerRestore[%d], Name=%s」の後には 10 進数と文字列の引数が必要ですが、文字列の引数しか与えられないため、これは確かに問題を引き起こす可能性があると思います。私はいくつかのテストを行う必要がありますが、このコードを書いた作者は次のように書くつもりだったと確信しています:

FileLog( "TimerRestore[%d], Name=%s", Index, Package.CurGame->Timers[ Index ].Name.c_str() );

ただし、関数呼び出しが常にエラーになるとは限らない理由はまだわかりません。または、FileLog 関数の "ReEntrant" 変数が失敗しないときにブロックしていることが原因でしょうか?

すべてのフィードバックと情報に感謝します。

4

4 に答える 4

8

vprintf()(および友人)va_list引数として使用できるようにします。これは、関数に可変量の引数がある場合に役立ちます。

void log(FILE *file, const char* format, ... )
{
  va_list args;
  va_start (args, format);
  fprintf(file, "%s: ", getTimestamp());
  vfprintf (file, format, args);
  va_end (args);
}

アプリケーションでは、可変量の引数を指定してこの関数を呼び出すことができます。

log(file, "i=%d\n", i);           // 3 arguments
log(file, "x=%d, y=%d\n", x, y);  // 4 arguments

関数がエラーになる理由がわかりません。あなたのコード スニペットは十分な詳細を提供していません。提供された関数引数の型の量が原因である可能性があります。

于 2013-01-16T12:33:21.737 に答える
2

まずfprintf()、(特に) vfprintf()C++ で and を使用するのは悪です。

要点:fprintf()は可変引数関数であり、任意の数の引数を受け入れます。va_list内部的には、 、 、va_start()を使用して可変引数を「アンパック」することにより、可変引数関数が実装されますva_end()

vfprintf()独自の可変引数をアンパックした (つまり、インスタンスにアクセスできる)fprintf()、独自の可変引数関数からの機能にアクセスする場合に使用します。可変長ではありません。引数の格納を受け入れます。va_listvfprintf()va_list

fprintf()andを呼び出す関数の宣言を投稿していませんが、vfprintf()可変長であると想定できます。最初に を使用fprintf()していくつかのデータを に出力し、LogFile次に を使用vfprintf()して独自の可変引数をそこに出力します。

于 2013-01-16T12:38:44.470 に答える
0

これはロギングではかなり一般的です。次のような printf スタイルのログ メッセージを作成します。

Log("The value of x is now %d", x);

しかし、それには可変引数が必要です。だからあなたが必要vfprintfです。同様に使用される理由fprintfは、日付/時刻スタンプを書きたいためであり、渡された既存の形式にその余分なものを追加できないためvfprintfです。

これを行う別の方法は、文字列 version を使用しvsprintfて 1 つの大きな文字列を作成し、それをファイルに書き込むことです。ただし、これはエラー (バッファー オーバーフローなど) が発生しやすくなります。

于 2013-01-16T12:36:44.627 に答える
0

vfprintf実行時にパラメータのリストを動的に作成できることを意味する可変引数リストを持つことができます。

于 2013-01-16T12:33:26.197 に答える