有没有更好的方法将格式化的输出传递给OutputDebugString? [英] Is there a better way to pass formatted output to OutputDebugString?
问题描述
通常,当我需要在Windows中调试输出时,我使用以下C代码段:
Typically, when I need to do debug output in Windows, I use the following C code segment:
#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};
)有点粗略,因为它可能比分配的内存消耗更多或更少的内存,或者截断输出或浪费内存.我编写了以下代码来解决所有这些问题,但是由于宏有点大,所以使我感到关注.
I'd like to recode this to use OutputDebugString
which doesn't accept a format string. I consider statically allocating a small array on the stack (e.g., WCHAR wszBuf[100] = {0};
) to be somewhat crude since it might consume significantly more or less memory than what is allocated and either truncate output or waste memory. I wrote the following code that addresses all of these concerns, but concerns me because the macro is a bit large.
#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并从那里计算出正确的大小.
- 我使用了宏,因为我不相信使用函数时有一种简单的方法可以达到相同的结果.
我的问题很简单,由于某个原因或其他原因(尤其是由于规模或效率低下),此宏会被视为不良做法吗?如果是这样,我应该考虑哪些替代方案?
My question is, quite simply, would this macro be considered bad practice for one reason or another (particularly for size or inefficiency)? If so, what alternatives should I be considering?
万一其他人想知道,我使用了注释中的建议和选定的答案,并提出了以下代码.非常感谢所有发表评论或回答的人-如果您想共享一个聪明的方法,请随时添加更多内容!
In case anyone else is wondering, I used the suggestions from the comments and the selected answer and came up with the following code. Thank you so much to everyone who commented or answered - feel free to add more if you have a clever way of doing this that you want to share!
#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
推荐答案
如果您将所有代码放入普通的varargs函数中,然后在宏中调用该代码,则这样会更简单,并且更不会出错:
It would be much simpler and less error prone if you'd put all the code into a normal varargs function and then called that in your macro, similar to this:
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__)
这篇关于有没有更好的方法将格式化的输出传递给OutputDebugString?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!