The less bugs the program, the higher the end-user's evaluation of the program. And the more developers are dealing with bugs in advance, the more information the end user can provide about bugs, the more accurate the developer will be able to quickly find the part of the code that appears bugs and release the program's upgrade package as soon as the end user is reflected.
In this tutorial, we start with the basics and step through the many principles of "should do" or "not be done" when debugging a program. As you'll see, the term "debug" in this tutorial contains a lot of meaning, not just as most people think--using debug from the IDE's integrated debugger. I hope that after reading this tutorial, the reader can gain some ideas.
Write easy to read code
The 1th, and probably the most important, is to write clean, readable code. Readable code is valuable. Imagine, if you just glance at the code or comment, you can immediately know the role of the Code, as well as in the writing code why to write this, then the idea is what, then can save a lot of time. Such code may be slightly slower to write, but when you debug a program, you won't spend hours looking for bugs, and instead, you can quickly and easily get the job done. At this point, you will find it worthwhile to spend more time making the program easier to read.
So, I recommend that when you write a program, you should develop your own style, or read Scott's article about code style.
How to use exceptions and exception
The next step in our tutorial is still based on the code. Because of the few cases, developers cannot always rely on integrated debugging tools. So it's important to learn to find annoying bugs in other ways. Some important, processed errors may occur outside of the form. In the dark days before the C + + standard was worked out, the error signal was emitted in the program, usually by returning an error code (which is still applied to OLE technology and some WINAPI functions), which can easily be ignored. (For example, do you often check the return value of the WINAPI function?) Therefore, there is no small likelihood of problems. For the above reasons, we need a mechanism that allows us to ignore these errors, and this mechanism should be controlled and customized by us. In such a demand, the exception handling mechanism appears. Do you need a special type of error? Simply, it's OK to define a new exception type (similar to the method that defines a class), and then throw (throw) it. The following example illustrates this process.
Example 1:
//----------------------------------------------------------------
class MyException
{
public:
AnsiString iMessage;
MyException(AnsiString Message) { iMessage=Message;}
};
throw new MyException(“Test Exception Message”);
//---------------------------------------------------------------
That's it! (Not very well, we will continue to refine it below). Simple and efficient, and easy to customize. Perhaps you will now ask: "I can make exceptions, but how do I control them?" I mean, I want to exclude exceptions at the very front of the code. "C++builder defines a try {} catch (...) for us. {} mechanism. This is similar to the structure of the exception mechanism we have just defined. This mechanism can be customized as needed. To use exception handling, you need to define a catch () or __finally block as long as you put the code you want to execute into a try block, in order to let the program know what to do after the exception occurs. The catch () statement can specify a type or variable to catch (for example 1, catch (MyException &e) {/* Exception handling code/} The mechanism is powerful and can even be used to capture the tree structure or inherited class exceptions, if the base class exception is captured, It captures the exception of all classes that inherit the base class. For example, in VCL, all exceptions are inherited from the exception class. Therefore, catch (exception& E) can catch all VCL exceptions except Esocketerror. (Please pay special attention to this and continue the discussion later.) In order to make this mechanism more powerful, the C++builder also defines catch (...). Statement. (yes, that's three points) use this statement to catch all the exceptions. Do you have more features? Of course, you can add more catch () statements to the use of If...else if ... Statement to use it in the same way. Note that in a series of catch () statements, errors are not caught repeatedly, that is, if the preceding catch () statement catches an error, the subsequent catch () statement will not catch the error.
Example 2:
//----------------------
try
{
// 正常代码
}
catch(EDBEngineError &E)
{
// 处理数据库引擎错误
}
catch(EExternalError &E)
{
// 处理窗口类的错误
}
catch(Exception &E)
{
// 处理所有的VCL错误
}
//----------------------
Take a look at Example 2, where the code runs the process: "is the error edbengineerror?" Is-> deal with it. Not-> run the next catch statement "" is Eexternalerror? Is-〉 deal with it. Not-〉 run the next catch statement "and so on.
There are more features in this mechanism. If you want to handle an exception, but do not want to stop at the location of the processing, you can throw the exception again. At this point, the program continues to look for the next catch () statement to handle the exception. This method is similar to "throw". In this way, the exception that you have handled will be thrown again, and continue to look for the next catch statement to handle it.
The last one to say is __finally (this is not standard usage, is a good way to add Borland), in the __finally{} program block code, whether or not an exception will be executed. This is a local variable in the cleanup program that is allocated using new, and setting the variable value used as the flag is a good location. (for example, set the cursor icon for a waiting state to the normal cursor.) )
This is it. If you have time, look at the exception class in the C++builder help file and the classes that inherit exception. These will be helpful in understanding what is said in this section.
Using the logging mechanism
You can't always debug your code with a debugger, and in some cases you may not be able to use an internally integrated debugger, and then you have to rely on other means to debug the program. (e.g. Windows NT services, isapi/cgi programs, live applications, etc.). At this time, experienced programmers may use the old debugging methods, for example, using some sort of recording mechanism to determine the actual operation of the program process. We are fortunate that there are a number of ways to do this work simply. Here are 3 of my favorite methods.
The first one: OutputDebugString. (Winapi:void OutputDebugString (LPCTSTR lpoutputstring); Fortunately, Microsoft has completely implemented the debugging subsystem. It includes some features that might make you want to throw away your own recording system. When the application runs in the debugger process, OutputDebugString will print out the information that the debugger outputs with a C string. If the program does not run in the debugger process, it ignores those calls. It will be good to run on the client's machine and will not eject the information window. If you're posting to a customer, forgetting to remove the code will only slow down, with no other adverse consequences.
The second method: Using Gexperts, debugging through the Dbugint.pas interface. It's a great program that you can distribute to customers. Like OutputDebugString, if the customer does not have this program, it does nothing at all. (It automatically detects whether the client is installed on the machine). To use dbugintf, it's easy to be added to your project by adding #include "dbugintf." HPp "(To add it to the project and then compile it with Pascal files). You can then use the Senddebug directly (the string to be sent to the record file); Or, you need it to be more alert, and you can use Senddebugex (it adds a new message type to Tmsgdlgtype) Sendmethodenter, Sendmethodexit, Sendseparator, and so on (the usage is similar). If you are going to distribute the client to the end user (Gdebug.exe), do not forget to include the package you want. Gexperts can be obtained in http://www.gexperts.org, it is free.
The third, probably the toughest way, is to use your own record control. This method may not be as simple as you think. You might think first of all, "throw a richedit on a form, set it to read-only, and write a record in it." Theoretically good, but, put it ... First, logging with the RichEdit control can greatly reduce the speed of your application, and it can also cause fragmentation and even loss of memory in memory. Typically, after 10 minutes of running, the entire computer slows down! (This is a crime!) So if you want to be able to use color and icons in your own records, it's best to create a component yourself. If there is no such high requirement, then there is a simple and effective way to use the ListBox control to record, set the ListBox's Style property to Lbownerdrawfixed, so that the handle will be painted. (Gexperts's console is made in this way).