有没有更好的方法将格式化输出传递给OutputDebugString?

Kev*_*vin 3 c debugging winapi visual-studio-debugging visual-studio-macros

通常,当我需要在Windows中进行调试输出时,我使用以下C代码段:

#ifdef _DEBUG
#define DBGPRINT( kwszDebugFormatString, ... ) \
{ \
    wprintf_s( L"[%s:%d] ", __FUNCTIONW__, __LINE__ ); \
    wprintf_s( kwszDebugFormatString, __VA_ARGS__ ); \
}
#else
#define DBGPRINT( kwszDebugFormatString, ...) ;;
#endif
Run Code Online (Sandbox Code Playgroud)

我想重新编码使用OutputDebugString不接受格式字符串.我认为静态地在堆栈上分配一个小数组(例如WCHAR wszBuf[100] = {0};)有些粗糙,因为它可能消耗比分配的内存更多或更少的内存,并截断输出或浪费内存.我编写了以下代码来解决所有这些问题,但我担心因为宏有点大.

#ifdef _DEBUG
#define DBGPRINT( kwszDebugFormatString, ... ) \
{ \
    INT iLineNumber = __LINE__; \
    FILE *fileNul = NULL; \
    INT cbFormatString = 0; \
    PWCHAR wszDebugString = NULL; \
    size_t st_Offset = 0; \
    \
    /* Determine the number of characters in the format string by writing to NUL. */\
    fopen_s( &fileNul, "nul", "w" ); \
    cbFormatString = fwprintf_s( fileNul, L"[%s:%d]", __FUNCTIONW__, iLineNumber ) * sizeof( WCHAR ); \
    cbFormatString += fwprintf_s( fileNul, kwszDebugFormatString, __VA_ARGS__ ) * sizeof( WCHAR ) + 2; \
    \
    /* Depending on the size of the format string, allocate space on the stack or the heap. */ \
    wszDebugString = (PWCHAR)_malloca( cbFormatString ); \
    \
    /* Populate the buffer with the contents of the format string. */ \
    StringCbPrintfW( wszDebugString, cbFormatString, L"[%s:%d]", __FUNCTIONW__, iLineNumber ); \
    StringCbLengthW( wszDebugString, cbFormatString, &st_Offset ); \
    StringCbPrintfW( &wszDebugString[st_Offset / sizeof(WCHAR)], cbFormatString - st_Offset, kwszDebugFormatString, __VA_ARGS__ ); \
    \
    OutputDebugStringW( wszDebugString ); \
    \
    _freea( wszDebugString ); \
    fclose( fileNul ); \
}
#else
#define DBGPRINT( kwszDebugFormatString, ... ) ;;
#endif
Run Code Online (Sandbox Code Playgroud)

几点说明:

  • 我使用_malloca()和_freea(),以便在输出足够小时可以使用堆栈分配.
  • 我不知道有任何方法可以获得完全展开的格式字符串的正确大小.我能想到的最好的解决方案是将其转储到NUL并从那里计算出正确的尺寸.
  • 我使用了一个宏,因为我不相信在使用函数时有一种简单的方法可以实现相同的结果.

我的问题很简单,因为某种原因(特别是尺寸或效率低下),这个宏会被视为不良做法吗?如果是这样,我应该考虑哪些替代方案?

如果其他人想知道,我使用了评论和所选答案中的建议,并提出了以下代码.非常感谢所有评论或回答的人 - 如果你有一个聪明的方法想要分享,请随意添加更多!

#ifdef _DEBUG
#define DBGPRINT(kwszDebugFormatString, ...) _DBGPRINT(__FUNCTIONW__, __LINE__, kwszDebugFormatString, __VA_ARGS__)

VOID _DBGPRINT( LPCWSTR kwszFunction, INT iLineNumber, LPCWSTR kwszDebugFormatString, ... ) \
{
    INT cbFormatString = 0;
    va_list args;
    PWCHAR wszDebugString = NULL;
    size_t st_Offset = 0;

    va_start( args, kwszDebugFormatString );

    cbFormatString = _scwprintf( L"[%s:%d] ", kwszFunction, iLineNumber ) * sizeof( WCHAR );
    cbFormatString += _vscwprintf( kwszDebugFormatString, args ) * sizeof( WCHAR ) + 2;

    /* Depending on the size of the format string, allocate space on the stack or the heap. */
    wszDebugString = (PWCHAR)_malloca( cbFormatString );

    /* Populate the buffer with the contents of the format string. */
    StringCbPrintfW( wszDebugString, cbFormatString, L"[%s:%d] ", kwszFunction, iLineNumber );
    StringCbLengthW( wszDebugString, cbFormatString, &st_Offset );
    StringCbVPrintfW( &wszDebugString[st_Offset / sizeof(WCHAR)], cbFormatString - st_Offset, kwszDebugFormatString, args );

    OutputDebugStringW( wszDebugString );

    _freea( wszDebugString );
    va_end( args );
}
#else
#define DBGPRINT( kwszDebugFormatString, ... ) ;;
#endif
Run Code Online (Sandbox Code Playgroud)

sth*_*sth 7

如果你将所有代码放入一个普通的varargs函数然后在你的宏中调用它会更简单,更不容易出错,类似于:

void dbgprint(const wchar_t *func, int line, const wchar_t *fmt, ...) {
   // Fomat the string, maybe with vsprintf, log it, etc.
}

#define DBGPRINT(fmt, ...) dbgprint(__WFUNCTION__, __LINE__, fmt, __VA_ARGS__)
Run Code Online (Sandbox Code Playgroud)

  • @alk - 我的意思是说,当你提出这个时,我认为你指的是类似于`#define void foo(){}`的东西,但我从没想过定义一个(因为没有更好的术语)'传递与位置相关的参数时,简单地映射到实际函数的"宏函数".这是我喜欢发现的C中这些微妙聪明的东西:-) (2认同)

小智 6

我目前正在使用这种方式。简单快速。非常简单:)

#define MY_PRINTF(...) {char cad[512]; sprintf(cad, __VA_ARGS__);  OutputDebugString(cad);}
Run Code Online (Sandbox Code Playgroud)