88

テキストをフォーマットする「エラー」関数を保持するクラスがあります。可変数の引数を受け入れてから、printf を使用してそれらをフォーマットしたいと考えています。

例:

class MyClass
{
public:
    void Error(const char* format, ...);
};

Error メソッドはパラメーターを受け取り、printf/sprintf を呼び出してフォーマットし、それに対して何かを行う必要があります。すべての書式設定を自分で書きたくないので、既存の書式設定を使用する方法を試してみることは理にかなっています。

4

7 に答える 7

166
void Error(const char* format, ...)
{
    va_list argptr;
    va_start(argptr, format);
    vfprintf(stderr, format, argptr);
    va_end(argptr);
}

表示する前に文字列を操作し、最初にバッファに保存する必要がある場合は、vsnprintf代わりにvsprintf. vsnprintf偶発的なバッファ オーバーフロー エラーを防ぎます。

于 2009-06-29T03:22:21.287 に答える
42

vsnprintf を見てください

最初に va_list arg 配列を初期化してから呼び出す必要があります。

そのリンクの例: /* vsprintf の例 */

#include <stdio.h>
#include <stdarg.h>

void Error (char * format, ...)
{
  char buffer[256];
  va_list args;
  va_start (args, format);
  vsnprintf (buffer, 255, format, args);


  //do something with the error

  va_end (args);
}
于 2009-06-29T03:15:46.790 に答える
4

スタックオーバーフローの既存の質問についてもっと読むべきでした。

C++ Passing Variable Number of Argumentsも同様の質問です。Mike F は次のように説明しています。

いたずらで移植性のないトリックを使用したい場合を除き、渡される引数の数を知らずに (たとえば) printf を呼び出す方法はありません。

一般的に使用される解決策は、vararg 関数の代替形式を常に提供することです。そのため、printf には ... の代わりに va_list を取る vprintf があります。 ... バージョンは、va_list バージョンの単なるラッパーです。

これはまさに私が探していたものです。次のようなテスト実装を実行しました。

void Error(const char* format, ...)
{
    char dest[1024 * 16];
    va_list argptr;
    va_start(argptr, format);
    vsprintf(dest, format, argptr);
    va_end(argptr);
    printf(dest);
}
于 2009-06-29T03:15:51.627 に答える
4

variadic functionsを探しています。printf() と sprintf() は可変引数関数です。可変数の引数を受け入れることができます。

これには、基本的に次の手順が必要です。

  1. 最初のパラメーターは、後続のパラメーターの数を示す必要があります。したがって、printf() では、"format" パラメータがこの指標を示します。5 つの書式指定子がある場合は、さらに 5 つの引数 (合計 6 つの引数) を探します。最初の引数は整数にすることができます (たとえば、"myfunction (3, a, b, c)" ここで、"3" は "3 つの引数)

  2. 次に、va_start() などの関数を使用してループし、連続する各引数を取得します。

これを行う方法に関するチュートリアルはたくさんあります - がんばってください!

于 2009-06-29T03:17:13.153 に答える
2

楕円で関数を使用することは、あまり安全ではありません。ログ関数のパフォーマンスが重要でない場合は、boost::formatのように演算子のオーバーロードを使用することを検討してください。あなたはこのようなものを書くことができます:

#include <sstream>
#include <boost/format.hpp>
#include <iostream>
using namespace std;

class formatted_log_t {
public:
    formatted_log_t(const char* msg ) : fmt(msg) {}
    ~formatted_log_t() { cout << fmt << endl; }

    template <typename T>
    formatted_log_t& operator %(T value) {
        fmt % value;
        return *this;
    }

protected:
    boost::format                fmt;
};

formatted_log_t log(const char* msg) { return formatted_log_t( msg ); }

// use
int main ()
{
    log("hello %s in %d-th time") % "world" % 10000000;
    return 0;
}

次のサンプルは、省略記号で発生する可能性のあるエラーを示しています。

int x = SOME_VALUE;
double y = SOME_MORE_VALUE;
printf( "some var = %f, other one %f", y, x ); // no errors at compile time, but error at runtime. compiler do not know types you wanted
log( "some var = %f, other one %f" ) % y % x; // no errors. %f only for compatibility. you could write %1% instead.
于 2009-06-29T05:43:31.477 に答える
2

以下の簡単な例。より大きなバッファーを渡して、バッファーが十分に大きいかどうかをテストする必要があることに注意してください。

void Log(LPCWSTR pFormat, ...) 
{
    va_list pArg;
    va_start(pArg, pFormat);
    char buf[1000];
    int len = _vsntprintf(buf, 1000, pFormat, pArg);
    va_end(pArg);
    //do something with buf
}
于 2009-06-29T03:17:12.810 に答える
0

http://www.cplusplus.com/reference/clibrary/cstdarg/va_arg/の例を見てください。引数の数をメソッドに渡しますが、それを省略してコードを適切に変更できます (例を参照)。

于 2009-06-29T03:16:28.223 に答える