有没有更好的方法将格式化输出传递给 OutputDebugString?
Is there a better way to pass formatted output to OutputDebugString?
通常,当我需要在 Windows 中进行调试输出时,我使用以下 C 代码段:
#ifdef _DEBUG
#define DBGPRINT( kwszDebugFormatString, ... ) \
{ \
wprintf_s( L"[%s:%d] ", __FUNCTIONW__, __LINE__ ); \
wprintf_s( kwszDebugFormatString, __VA_ARGS__ ); \
}
#else
#define DBGPRINT( kwszDebugFormatString, ...) ;;
#endif
我想重新编码以使用不接受格式字符串的 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
一些注意事项:
- 我使用了 _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
如果您将所有代码放入一个普通的可变参数函数中,然后在您的宏中调用它,将会更简单并且更不容易出错,类似于:
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__)
我目前正在使用这种方式。简单快捷。简单得离谱:)
#define MY_PRINTF(...) {char cad[512]; sprintf(cad, __VA_ARGS__); OutputDebugString(cad);}
通常,当我需要在 Windows 中进行调试输出时,我使用以下 C 代码段:
#ifdef _DEBUG
#define DBGPRINT( kwszDebugFormatString, ... ) \
{ \
wprintf_s( L"[%s:%d] ", __FUNCTIONW__, __LINE__ ); \
wprintf_s( kwszDebugFormatString, __VA_ARGS__ ); \
}
#else
#define DBGPRINT( kwszDebugFormatString, ...) ;;
#endif
我想重新编码以使用不接受格式字符串的 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
一些注意事项:
- 我使用了 _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
如果您将所有代码放入一个普通的可变参数函数中,然后在您的宏中调用它,将会更简单并且更不容易出错,类似于:
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__)
我目前正在使用这种方式。简单快捷。简单得离谱:)
#define MY_PRINTF(...) {char cad[512]; sprintf(cad, __VA_ARGS__); OutputDebugString(cad);}