One of the most significant problems most programmers face during application development is debugging the code. As a result, Borland C++ supplies a strong set of debugging tools to help locate code problems.
Borland C++ 4.0 provides two new diagnostic macros that can help you embed diagnostic messages and conditional messages in your functions. In this article, we'll show you how to add these new macros to your code and how to turn them on and off when you compile the application.
Many programmers like to embed debugging or diagnostic code directly in their programs. Some programmers do this because they're unfamiliar with Borland's debugging tools. Others embed diagnostic code so they can analyze complex bugs in the true native environment for the application.
Unfortunately, if you add diagnostic code to a specific function, it may significantly reduce the speed of the function's execution. Due to speed considerations, you may have to remove the diagnostic code after you debug the production version of your application, only to reenter the code when a new bug appears.
For some time now, programmers have been surrounding diagnostic code with conditional-compile statements. These usually take the form
<pre>
#ifdef DIAGNOSTIC
if(param == 0)
cout
</pre>
This way, if you add a #define statement for the label DIAGNOSTIC early in the file, the compiler will see and process the error-checking code. If you remove the #define statement for DIAGNOSTIC, the preprocessor skips to the #endif statement and the compiler never sees the code.
However, adding conditional-compile statements can be a very tedious process. If you don't add the #define statement at the correct location in the file, or if you misspell the label, the preprocessor may skip over the diagnostic code for an important function.
Finally, if you decide to send your diagnostic messages to a file instead of using the standard output stream cout or the printf() library function, you'll have to change each line of diagnostic code individually. Obviously, this isn't practical for a large application. Fortunately, Borland solves this problem with the two new macros TRACE and WARN.
Borland C++ 4.0 adds two new diagnostic macros TRACE and WARN that conditionally display messages and warnings at runtime. The CHECKS.H header file defines these macros.
To use those macros in your code, add a #include <checks.h> statement to your source files. Be sure to add this statement ahead of any functions that will use the diagnostic macros.
To enable the TRACE macro, be sure the label __TRACE appears in a #define statement. To enable the WARN macro, be sure the label __WARN appears in a separate #define statement. You can add these statements explicitly to your source files, or you can add the labels to the Defines list in the compiler's Options dialog box for that particular file.
The TRACE macro allows you to display simple diagnostic messages with the syntax
TRACE("Diagnostic Text");
Even in this form, the macro is an improvement over creating messages by hand. However, because the macro uses a member of the class strstream to format the output text, you can also write
TRACE("Diagnostic status "
<pre>
#include <owl/pch.h>
#include <fstream.h>
ofstream traceFile("trace.txt");
int foo(int param)
{
TRACE("Entering foo");
WARN(param, "param == "
</pre>
The first line is a #define statement for the __TRACE label, which enables the TRACE macro. Later, when we compile this program, we'll provide a #define statement by changing the compiler options for this file.
The next two lines in the program are #include statements that tell the preprocessor to embed the contents of CHECKS.H and FSTREAM.H in this file. The file CHECKS.H defines the diagnostic macros, and the file FSTREAM.H declares the ofstream class we'll use to create an output file stream for an error file.
Next, we declare a global ofstream object for the TRACE.TXT file. Later, we'll redirect the standard output file cout to send its output to this file.
The foo() function uses both the TRACE and the WARN macros to output text and the value of a variable. The main() function that follows calls the diagnostic macros with output text only.
At the very beginning of the main() function, you'll find the line
if(traceFile) cout = traceFile;
This statement checks to see if the output file stream traceFile is valid (no errors opening the file).
If the file is valid, we then assign the output file stream to the standard output stream cout to redirect its output to the file TRACE.TXT. Now, let's try our example.
In the Project window, right-click on the DIAG.CPP file's name. Now, choose Edit Local Options... from the pop-up menu.
When the Options: At DIAG.CPP dialog box appears, double-click on Compiler in the Topics list box. Then select Defines from the the same Topics list box and enter __WARN; in the Defines entry field. Click the OK button to save these settings.
Now, compile and run DIAG.EXE by double-clicking on its name in the Project window. When the IDE finishes compiling and linking the program, the screen will go black momentarily and then return to normal. (The screen goes black when the IDE runs this application as a DOS program under Windows. Because this program doesn't do anything except write some diagnostic messages to a file, it runs and then returns quickly.)
To see the output file, choose Open... from the IDE's File menu and then enter TRACE.TXT in the File Name entry field. When you click the OK button, an editor window for the file will appear, as shown here.
[-img src=Bcj1 3f2.gif: missing =-]
To remove the warning message code from DIAG.EXE, just remove the __WARN label from the DIAG.CPP file's compiler options. To remove the trace message code, remove the #define __TRACE statement at the beginning of the DIAG.CPP file.
By the way, there's nothing special about putting the #define __TRACE statement in the file and putting the __WARN label in the compiler options. You can put a #define __WARN statement in the source file and the __TRACE label in the compiler options, or you can put both in either location.
The TRACE and WARN macros give you more control over conditional-compile diagnostic messages than the #ifdef statements some programmers use. By taking advantage of these macros, you can develop the habit of leaving diagnostic code in your application without worrying about removing it from your production code.
Wiki: Knowledge_Base
Wiki: Using_the_extended_diagnostic_macros
The instructions for Borland C++ 4.0 need to be replaced with ones for a newer development environment, like Visual C++ 2008 or 2010 --[[User:Jogybl|Jogybl]] 16:55, 20 March 2010 (UTC)