43

と同じパラメータでデバッグロギング機能を作りたいprintfです。ただし、最適化されたビルド中にプリプロセッサによって削除できるもの。

例えば:

Debug_Print("Warning: value %d > 3!\n", value);

可変引数マクロを見てきましたが、すべてのプラットフォームで利用できるわけではありません。gccそれらをサポートしますが、msvcしません。

4

14 に答える 14

24

私は今でも昔ながらの方法で、no-op または可変引数リストを使用した関数呼び出しに対応するマクロ (以下の XTRACE) を定義しています。内部的に vsnprintf を呼び出して、printf 構文を維持できるようにします。

#include <stdio.h>

void XTrace0(LPCTSTR lpszText)
{
   ::OutputDebugString(lpszText);
}

void XTrace(LPCTSTR lpszFormat, ...)
{
    va_list args;
    va_start(args, lpszFormat);
    int nBuf;
    TCHAR szBuffer[512]; // get rid of this hard-coded buffer
    nBuf = _vsnprintf(szBuffer, 511, lpszFormat, args);
    ::OutputDebugString(szBuffer);
    va_end(args);
}

次に、典型的な #ifdef スイッチ:

#ifdef _DEBUG
#define XTRACE XTrace
#else
#define XTRACE
#endif

それはかなりきれいにすることができますが、それが基本的な考え方です。

于 2008-08-18T21:42:09.857 に答える
22

これは、C++ で出力をデバッグする方法です。次のように 'dout' (デバッグ アウト) を定義します。

#ifdef DEBUG
#define dout cout
#else
#define dout 0 && cout
#endif

コードでは、「cout」と同じように「dout」を使用しています。

dout << "in foobar with x= " << x << " and y= " << y << '\n';

プリプロセッサが 'dout' を '0 && cout' に置き換える場合、<< は && よりも優先順位が高く、&& の短絡評価により行全体が 0 に評価されることに注意してください。0 は使用されないため、コンパイラはコードをまったく生成しません。その行のために。

于 2008-09-15T21:58:48.033 に答える
11

これは私が C/C++ で行っていることです。まず、varargs を使用する関数を作成します (Stu の投稿のリンクを参照してください)。次に、次のようにします。


 int debug_printf( const char *fmt, ... );
 #if defined( DEBUG )
  #define DEBUG_PRINTF(x) debug_printf x
 #else
   #define DEBUG_PRINTF(x)
 #endif

 DEBUG_PRINTF(( "Format string that takes %s %s\n", "any number", "of args" ));

覚えておく必要があるのは、デバッグ関数を呼び出すときに二重括弧を使用することだけです。これにより、DEBUG 以外のコードでは行全体が削除されます。

于 2008-08-18T21:35:49.917 に答える
5

ああ、vsprintf() は私が見逃していたものでした。これを使用して、可変引数リストを直接 printf() に渡すことができます。

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

void DBG_PrintImpl(char * format, ...)
{
    char buffer[256];
    va_list args;
    va_start(args, format);
    vsprintf(buffer, format, args);
    printf("%s", buffer);
    va_end(args);
}

次に、全体をマクロでラップします。

于 2008-08-18T21:54:15.777 に答える
4

可変個引数関数をスタブ化するもう 1 つの楽しい方法は、次のとおりです。

#define function sizeof
于 2008-08-19T21:46:12.437 に答える
3

@CodingTheWheel:

あなたのアプローチには1つの小さな問題があります。次のような呼び出しを考えてみましょう

XTRACE("x=%d", x);

これはデバッグ ビルドでは正常に機能しますが、リリース ビルドでは次のように展開されます。

("x=%d", x);

これは完全に正当な C であり、通常は副作用なしでコンパイルおよび実行されますが、不要なコードが生成されます。その問題を解消するために私が通常使用するアプローチは次のとおりです。

  1. XTrace 関数が int を返すようにします (0 を返すだけで、戻り値は重要ではありません)。

  2. #else 句の #define を次のように変更します。

    0 && XTrace
    

リリース バージョンは次のように展開されます。

0 && XTrace("x=%d", x);

適切なオプティマイザーはすべてを破棄します。なぜなら、短絡評価は && の後の実行を妨げていたからです。

もちろん、最後の文を書いたとき、おそらく元のフォームも最適化されてしまう可能性があることに気付きました。XTrace にパラメーターとして渡される関数呼び出しなどの副作用の場合は、それがより良い解決策になる可能性があります。デバッグ バージョンとリリース バージョンが同じように動作することを確認してください。

于 2008-09-11T01:47:17.030 に答える
2

C++ では、ストリーミング演算子を使用して単純化できます。

#if defined _DEBUG

class Trace
{
public:
   static Trace &GetTrace () { static Trace trace; return trace; }
   Trace &operator << (int value) { /* output int */ return *this; }
   Trace &operator << (short value) { /* output short */ return *this; }
   Trace &operator << (Trace &(*function)(Trace &trace)) { return function (*this); }
   static Trace &Endl (Trace &trace) { /* write newline and flush output */ return trace; }
   // and so on
};

#define TRACE(message) Trace::GetTrace () << message << Trace::Endl

#else
#define TRACE(message)
#endif

次のように使用します。

void Function (int param1, short param2)
{
   TRACE ("param1 = " << param1 << ", param2 = " << param2);
}

に出力する場合とほぼ同じ方法で、クラスのカスタマイズされたトレース出力を実装できますstd::cout

于 2008-08-20T13:24:41.870 に答える
1

この種の機能の問題の一部は、多くの場合、可変長マクロを必要とすることです。これらはかなり最近 (C99) に標準化されましたが、古い C コンパイラの多くは標準をサポートしていないか、独自の回避策を講じています。

以下は、いくつかの優れた機能を備えた、私が書いたデバッグ ヘッダーです。

  • デバッグ マクロの C99 および C89 構文をサポート
  • 関数の引数に基づいて出力を有効/無効にする
  • ファイル記述子への出力(file io)

注: 何らかの理由で、コードの書式設定にわずかな問題がありました。

#ifndef _DEBUG_H_
#define _DEBUG_H_
#if HAVE_CONFIG_H
#include "config.h"
#endif

#include "stdarg.h"
#include "stdio.h"

#define ENABLE 1
#define DISABLE 0

extern FILE* debug_fd;

int debug_file_init(char *file);
int debug_file_close(void);

#if HAVE_C99
#define PRINT(x, format, ...) \
if ( x ) { \
if ( debug_fd != NULL ) { \
fprintf(debug_fd, format, ##__VA_ARGS__); \
} \
else { \
fprintf(stdout, format, ##__VA_ARGS__); \
} \
}
#else
void PRINT(int enable, char *fmt, ...);
#endif

#if _DEBUG
#if HAVE_C99
#define DEBUG(x, format, ...) \
if ( x ) { \
if ( debug_fd != NULL ) { \
fprintf(debug_fd, "%s : %d " format, __FILE__, __LINE__, ##__VA_ARGS__); \
} \
else { \
fprintf(stderr, "%s : %d " format, __FILE__, __LINE__, ##__VA_ARGS__); \
} \
}

#define DEBUGPRINT(x, format, ...) \
if ( x ) { \
if ( debug_fd != NULL ) { \
fprintf(debug_fd, format, ##__VA_ARGS__); \
} \
else { \
fprintf(stderr, format, ##__VA_ARGS__); \
} \
}
#else /* HAVE_C99 */

void DEBUG(int enable, char *fmt, ...);
void DEBUGPRINT(int enable, char *fmt, ...);

#endif /* HAVE_C99 */
#else /* _DEBUG */
#define DEBUG(x, format, ...)
#define DEBUGPRINT(x, format, ...)
#endif /* _DEBUG */

#endif /* _DEBUG_H_ */
于 2008-09-03T22:50:00.043 に答える
1

このスレッドを見てください:

それはあなたの質問に答えるはずです。

于 2009-03-27T12:55:05.580 に答える
1

利用できないプラットフォームは? stdarg は標準ライブラリの一部です:

http://www.opengroup.org/onlinepubs/009695399/basedefs/stdarg.h.html

それを提供しないプラットフォームは、標準の C 実装ではありません (または非常に古いものです)。それらについては、varargs を使用する必要があります。

http://opengroup.org/onlinepubs/007908775/xsh/varargs.h.html

于 2008-08-18T21:27:18.793 に答える
0

今日問題に遭遇したので、私の解決策は次のマクロです。

    static TCHAR __DEBUG_BUF[1024];
    #define DLog(fmt, ...)  swprintf(__DEBUG_BUF, fmt, ##__VA_ARGS__); OutputDebugString(__DEBUG_BUF) 
  

次に、次のように関数を呼び出すことができます。

    int value = 42;
    DLog(L"The answer is: %d\n", value);
于 2012-10-22T21:25:52.037 に答える
0

質問で尋ねられていることとは正確には異なります。しかし、このコードはデバッグ目的に役立ちます。各変数の値をその名前とともに出力します。これは完全に型に依存せず、可変数の引数をサポートします。また、出力演算子をオーバーロードすると、STL の値を適切に表示することもできます。

#define show(args...) describe(#args,args);
template<typename T>
void describe(string var_name,T value)
{
    clog<<var_name<<" = "<<value<<" ";
}

template<typename T,typename... Args>
void describe(string var_names,T value,Args... args)
{
    string::size_type pos = var_names.find(',');
    string name = var_names.substr(0,pos);
    var_names = var_names.substr(pos+1);
    clog<<name<<" = "<<value<<" | ";
    describe(var_names,args...);
}

サンプル使用:

int main()
{
    string a;
    int b;
    double c;
    a="string here";
    b = 7;
    c= 3.14;
    show(a,b,c);
}

出力:

a = string here | b = 7 | c = 3.14 
于 2020-07-23T05:59:51.740 に答える
0

これは私が使用するものです:

inline void DPRINTF(int level, char *format, ...)
{
#    ifdef _DEBUG_LOG
        va_list args;
        va_start(args, format);
        if(debugPrint & level) {
                vfprintf(stdout, format, args);
        }
        va_end(args);
#    endif /* _DEBUG_LOG */
}

_DEBUG_LOG フラグがオフになっている場合、実行時にまったくコストがかかりません。

于 2013-08-08T15:00:42.357 に答える
0

これはユーザーの回答の TCHAR バージョンであるため、ASCII (通常) または Unicode モード (多かれ少なかれ) として機能します。

#define DEBUG_OUT( fmt, ...) DEBUG_OUT_TCHAR(       \
            TEXT(##fmt), ##__VA_ARGS__ )
#define DEBUG_OUT_TCHAR( fmt, ...)                  \
            Trace( TEXT("[DEBUG]") #fmt,            \
            ##__VA_ARGS__ )
void Trace(LPCTSTR format, ...)
{
    LPTSTR OutputBuf;
    OutputBuf = (LPTSTR)LocalAlloc(LMEM_ZEROINIT,   \
            (size_t)(4096 * sizeof(TCHAR)));
    va_list args;
    va_start(args, format);
    int nBuf;
    _vstprintf_s(OutputBuf, 4095, format, args);
    ::OutputDebugString(OutputBuf);
    va_end(args);
    LocalFree(OutputBuf); // tyvm @sam shaw
}

ASCII 文字列引数を WCHAR に自動的に変換しないため、「多かれ少なかれ」と言いますが、フォーマット文字列を TEXT() でラップしたり、前に L を付けたりすることを心配することなく、ほとんどの Unicode スクレイプから抜け出すことができます。 .

主に MSDNから派生: 最後のエラー コードの取得

于 2016-08-27T23:46:01.403 に答える