TRACE 宏可用于在调试模式下编译代码时向调试器输出诊断消息。在发布模式下我需要相同的消息。有没有办法做到这一点?
(请不要浪费时间讨论为什么我不应该在发布模式下使用 TRACE :-)
实际上,TRACE 宏比 OutputDebugString 灵活得多。它需要一个 printf() 样式的格式字符串和参数列表,而 OutputDebugString 只需要一个字符串。为了在发布模式下实现完整的 TRACE 功能,您需要执行以下操作:
void trace(const char* format, ...)
{
char buffer[1000];
va_list argptr;
va_start(argptr, format);
wvsprintf(buffer, format, argptr);
va_end(argptr);
OutputDebugString(buffer);
}
几年前,我需要类似的功能,所以我拼凑了以下代码。只需将它保存到一个文件中,例如 rtrace.h,将它包含在 stdafx.h 的末尾,并将 _RTRACE 添加到预处理器定义的发布模式中。
也许有人会发现它的用途:-)
约翰
#pragma 一次 //------------------------------------------------ ------------------------------------------------ // // 作者:约翰·卡伦 // 日期:2006/04/12 // 基于:变量参数列表的 MSDN 示例和 TRACE 的 ATL 实现。 // // 描述:允许在 RELEASE 构建中使用 TRACE 语句,通过覆盖 // 根据 RTRACE 类和重载的 TRACE 宏定义和重新定义 // 操作员 ()。通过直接调用 OutputDebugString() 生成跟踪输出。 // // // 用法:添加到 stdafx.h 的末尾,并将 _RTRACE 添加到预处理器定义中(通常 // 对于 RELEASE 构建,尽管对于 DEBUG 构建,该标志将被忽略。 // //------------------------------------------------ ------------------------------------------------ #ifdef _DEBUG // NL 定义为编写 FTRACE(_T("\n")); 的快捷方式 例如,改为写 FTRACE(NL); #define NL _T("\n") #define LTRACE TRACE(_T("%s(%d): "), __FILE__, __LINE__); 痕迹 #define FTRACE TRACE(_T("%s(%d): %s: "), __FILE__, __LINE__, __FUNCTION__); 痕迹 #else // _DEBUG #ifdef _RTRACE #undef 追踪 #define TRACE RTRACE() #define LTRACE RTRACE(__FILE__, __LINE__) #define FTRACE RTRACE(__FILE__, __LINE__, __FUNCTION__) #define NL _T("\n") RTRACE 类 { 上市: // 默认构造函数,无参数 RTRACE(void) : m_pszFileName( NULL ), m_nLineNo( 0 ), m_pszFuncName( NULL ) {}; // 重载构造函数、文件名和行号 RTRACE(PCTSTR const pszFileName,int nLineNo): m_pszFileName(pszFileName), m_nLineNo(nLineNo), m_pszFuncName(NULL) {}; // 重载构造函数、文件名、行号和函数名 RTRACE(PCTSTR const pszFileName,int nLineNo,PCTSTR const pszFuncName): m_pszFileName(pszFileName), m_nLineNo(nLineNo), m_pszFuncName(pszFuncName) {}; 虚拟 ~RTRACE(void) {}; // 没有传递参数,例如 RTRACE()() 无效运算符()()常量 { // 不传递参数,如果需要,只转储文件、行和函数 输出文件和线(); 输出函数(); } // 格式化字符串和传递的参数,例如 RTRACE()(_T("%s\n"), someStringVar) void operator()(const PTCHAR pszFmt, ...) const { // 如果需要,转储文件、行和函数,后跟 TRACE 参数 输出文件和线(); 输出函数(); // 执行标准的 TRACE 输出处理 va_list 指针;va_start(点,pszFmt); INT len = _vsctprintf(pszFmt, ptr) + 1; TCHAR* 缓冲区 = (PTCHAR) malloc( len * sizeof(TCHAR) ); _vstprintf(缓冲区,pszFmt,ptr); 输出调试字符串(缓冲区); 空闲(缓冲区); } 私人的: // 输出当前文件和行 内联 void OutputFileAndLine() 常量 { 如果 (m_pszFileName && _tcslen(m_pszFileName) > 0) { INT len = _sctprintf( _T("%s(%d): "), m_pszFileName, m_nLineNo ) + 1; PTCHAR 缓冲区 = (PTCHAR) malloc( len * sizeof(TCHAR) ); _stprintf(缓冲区, _T("%s(%d): "), m_pszFileName, m_nLineNo ); 输出调试字符串(缓冲区); 空闲(缓冲区); } } // 输出当前函数名 内联 void OutputFunction() 常量 { 如果 (m_pszFuncName && _tcslen(m_pszFuncName) > 0) { INT len = _sctprintf( _T("%s: "), m_pszFuncName ) + 1; PTCHAR 缓冲区 = (PTCHAR) malloc( len * sizeof(TCHAR) ); _stprintf(缓冲区, _T("%s:"), m_pszFuncName); 输出调试字符串(缓冲区); 空闲(缓冲区); } } 私人的: PCTSTR 常量 m_pszFuncName; PCTSTR 常量 m_pszFileName; const int m_nLineNo; }; #endif // _RTRACE #endif // NDEBUG
TRACE 只是OutputDebugString的一个宏。因此,您可以轻松地制作自己的 TRACE 宏(或称其为其他名称)来调用OutputDebugString。
这是我见过的最简单的代码
#undef ATLTRACE
#undef ATLTRACE2
#define ATLTRACE2 CAtlTrace(__FILE__, __LINE__, __FUNCTION__)
#define ATLTRACE ATLTRACE2
在 MFC 中,TRACE 被定义为 ATLTRACE。在定义为的发布模式下:
#define ATLTRACE __noop
因此,使用 MFC 的开箱即用 TRACE,您实际上无法读取任何 TRACE 文本,因为它甚至不会被写出。您可以编写自己的 TRACE 函数,然后重新定义 TRACE 宏。你可以这样做:
void MyTrace(const CString& text)
{
::OutputDebugString(text); // Outputs to console, same as regular TRACE
// TODO: Do whatever output you need here. Write to event log / write to text file / write to pipe etc.
}