Is there a TRACE statement for basic win32 C++?
Asked Answered
R

7

8

In MFC C++ (Visual Studio 6) I am used to using the TRACE macro for debugging. Is there an equivalent statement for plain win32?

Radiotelegram answered 16/1, 2009 at 20:0 Comment(1)
why does anyone still use visual studio 6 these days. The 2005 and now 2008 have been free for a long time.Iphagenia
R
9

_RPTn works great, though not quite as convenient. Here is some code that recreates the MFC TRACE statement as a function allowing variable number of arguments. Also adds TraceEx macro which prepends source file and line number so you can click back to the location of the statement.

Update: The original code on CodeGuru wouldn't compile for me in Release mode so I changed the way that TRACE statements are removed for Release mode. Here is my full source that I put into Trace.h. Thanks to Thomas Rizos for the original:

// TRACE macro for win32
#ifndef __TRACE_H__850CE873
#define __TRACE_H__850CE873

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

#ifdef _DEBUG
#define TRACEMAXSTRING  1024

char szBuffer[TRACEMAXSTRING];
inline void TRACE(const char* format,...)
{
    va_list args;
    va_start(args,format);
    int nBuf;
    nBuf = _vsnprintf(szBuffer,
                   TRACEMAXSTRING,
                   format,
                   args);
    va_end(args);

    _RPT0(_CRT_WARN,szBuffer);
}
#define TRACEF _snprintf(szBuffer,TRACEMAXSTRING,"%s(%d): ", \
                &strrchr(__FILE__,'\\')[1],__LINE__); \
                _RPT0(_CRT_WARN,szBuffer); \
                TRACE
#else
// Remove for release mode
#define TRACE  ((void)0)
#define TRACEF ((void)0)
#endif

#endif // __TRACE_H__850CE873
Radiotelegram answered 16/1, 2009 at 20:35 Comment(4)
szBuffer should not be global if you are using TRACE in more than one threadFrangible
good point -- I think if I just move the declaration inside the TRACE function it will break the TRACEF macro though -- is this true?Radiotelegram
If C++ is an option you might want to consider using a std::vector instead of a fixed size buffer. Note that this change potentially introduces C++ exceptions. _scprintf returns the required buffer size.Medieval
this will fail at runtime if __FILE__ does not contain a backslash. See FILE macro shows full path for a fix.Jasmine
C
3

From the msdn docs, Macros for Reporting:

You can use the _RPTn, and _RPTFn macros, defined in CRTDBG.H, to replace the use of printf statements for debugging. These macros automatically disappear in your release build when _DEBUG is not defined, so there is no need to enclose them in #ifdefs.

Cardigan answered 16/1, 2009 at 20:5 Comment(0)
N
3

There is also OutputDebugString. However that will not be removed when compiling release.

Northernmost answered 16/1, 2009 at 22:16 Comment(0)
M
2

Trace macros that provide messages with source code link, run-time callstack information, and function prototype information with parameter values:

Extended Trace: Trace macros for Win32

Monaghan answered 30/1, 2009 at 9:30 Comment(0)
V
2

I just use something like this (from memory, not tested at all...)

#define TRACE(msg) {\
    std::ostringstream ss; \
    ss << msg << "\n"; \
    OutputDebugString(msg.str()); \
}

And then I can write things like :-

TRACE("MyClass::MyFunction returned " << value << " with data=" << some.data);

You can wrap that in some #ifdefs to remove it in release builds easily enough.

Veron answered 31/10, 2012 at 15:8 Comment(1)
Just a little fix:OutputDebugString(ss.str().c_str()); should be used instead of OutputDebugString(msg.str());Abdias
B
1

I found that using the _RPT() macro will also work with a C source file in Visual Studio 2005. This article Debugging with Visual Studio 2005/2008: Logging and Tracing provides an overview of TRACE, _RPT, and other logging type macros.

I generate a line for a log file called the ASSRTLOG which contains logs and when writing the log to the file, I also do the following source code line:

_RPT1(_CRT_WARN, "ASSRTLOG: %s", szLog1);

This line puts the same log that is going into the log file into the output window of the Visual Studio 2005 IDE.

You might be interested in the mechanics behind the approach we are using for logging. We have a function PifLogAbort() which accepts a series of arguments that are then used to generate a log. These arguments include the name of the file where the log is being generated along with the line number. The macro looks like this:

#define NHPOS_ASSERT_TEXT(x, txt) if (!(x)) { PifLogAbort( (UCHAR *)  #x , (UCHAR *)  __FILE__ , (UCHAR *) txt , __LINE__ );}

and the function prototype for PifLogAbort() look like this:

PifLogNoAbort(UCHAR *lpCondition, UCHAR *lpFilename, UCHAR *lpFunctionname, ULONG ulLineNo)

and to use the macro we will insert a line like this:

NHPOS_ASSERT_TEXT(sBRetCode >= 0, "CliEtkTimeIn():  EtkTimeIn() returned error");

What this macro will do is that if the return code is less than 0 (the assertion fails), a log will be generated with the provided text. The log includes the condition that generated the log along with file name and line number.

The function PifLogAbort() generates logs with a specified length and treats the output file as a circular buffer. The logs have a time and date stamp as well.

In those cases where we want to generate the descriptive text dynamically at run time, perhaps to provide the actual error code value, we use the sprintf() function with a buffer as in the following code sequence:

if (sErrorSave != STUB_BM_DOWN) {
    char xBuff[128];
    sprintf(xBuff, "CstSendBMasterFH: CstComReadStatus() - 0x%x, sError = %d", usCstComReadStatus, CliMsg.sError);
    NHPOS_ASSERT_TEXT((sErrorSave == STUB_BM_DOWN), xBuff);
}

If we want the logs to not be generated, all we need to do is to go to the single header file where the macro is defined and define it to be nothing then recompile. However we have found that these logs can be very valuable when investigating field issues and are especially useful during integration testing.

Bogusz answered 31/10, 2012 at 15:1 Comment(0)
M
1

Windows Events are a potential replacement for TRACE macros, depending on your particular scenario. The code gets compiled into both Debug and Release configurations. Event tracing can then be dynamically enabled and disabled, displayed in real-time, or dumped on a client's machine for later diagnosis. The traces can be correlated with trace information gathered from other parts of the OS as well.

If you merely need to dump information whenever code reaches certain checkpoints, together with variable content, stack traces, or caller names, Visual Studio's Tracepoints are a non-intrusive option to do so.

Medieval answered 9/12, 2014 at 14:13 Comment(2)
The link 'TracePoints' do not work for me. 403 ForbiddenLatinist
@TomTom Updated the link to point to a different resource. Let's hope this one stays around for a bit longer.Medieval

© 2022 - 2024 — McMap. All rights reserved.