Use debug speech in the VC program
In order to better debug program, you can use the following methods: use assertions, use tracking statements, use exceptions and return values.
First, assertion
1. Basic concept
As an assertion is a simple and effective technique that makes mistakes in the running of self-exposure. They help you find errors earlier, making the entire debugging process efficient.
As a Boolean trial statement, it is used to detect whether the value of a certain condition is always true when the program is running normally. It allows errors to expose in front of the programmer at runtime. The biggest advantage of using assertions is that you can discover errors in a place where the wrong origin is more resolved. As a result of the following characteristics:
The assertion is used to find the runtime error, and the discovered error is about the program implementation.
The Boolean expression in asserts displays an effectiveness of an object or state rather than the correctness.
As an assertion that exists only in the debug version after conditioning, not the release version.
As an assertion that cannot contain program code.
. As an assertion to provide information about the programmer rather than the user.
The most fundamental advantage of using assertions is to automatically discover the errors generated by many rules, but assertions cannot find all errors. As an assertion is the effectiveness of the program, not the correctness, and the error can be limited to a limited range by assertion. When assertion is fake, activation When the debugger displays the error code, you can use the call stack command to check the context, a small amount of related parameters, and the contents of the DEBUG table in the stack, usually, the cause of the assertion failed. _ASSERTE Macro (belonging to C running time library) can also display a failure assertion when asserting fails. Let's discuss the assertions in the MFC library.
2, the assertion in the MFC library
(1) ASSERT (Boolean expression)
It is best to choose an ASSERT macro when using MFC. It has the advantage that the assertion failure message box can be displayed even if a WM_QUIT message appears.
(2) Verify (Boolean expression)
The Boolean expression in the Verify macro is retained in the release version. The Verify macro simplifies the check of the function return value, generally used to check the return value of the Windows API. Because the Boolean expression in Verify is reserved in the release version, it is best not to use this macro to implement the full separation of the program code and debug code.
(3) Assert_Valid (pointing to a pointer to the COBJECT derived class object)
Assert_Valid macros determine if the key of the COBJECT derived class object is valid by calling an overloaded AssertValid function. No matter when you get an object from the COBJECT derived class, you should call the Assert_Valid macro before doing anything to do this object.
(4) Assert_kindof (class name, pointing to the pointer of the COBJECT derived class)
This macro is used to verify that the pointer to the COBJECT derived class object is derived from a special class, call the assert_valid macro before calling it. It is only available in a very special occasion, such as the object type problem that the compiler may miss.
In addition, there are two species of Assert macros without official files: assert_pointer, assert_null_or_pointer (pointer, pointer type).
3. When is it as an assertion?
As a simple manufacturing fence, this fence can expose when it passes itself.
Check the input of the function
Check the output of the function
Check the current state of the object
Adhere to the rationality and consistency of logical variables
Check the invariant in the class
The public member function requires a more comprehensive assertion than the private and protected member functions.
Use the assertion inappropriately causes errors. As an assertion should detect a state that will never appear when the program is running normally. As an assertion is used to reveal the wrong, not to correct the runtime error.
4, assertion and defensive programming (Defensive Programming)
As an assertion reveals the runtime error (in the debug version) when debugging, and the defensive programming user can continue to work when an unexpected situation occurs when an unexpected situation occurs. In fact, the defensive programming requires the program to return a "secure" value when detecting accidents (such as the Boolean function returns false, pointer and handle return null value), an error code or throw an exception to solve the problem. Specific defensive programming techniques include: processing invalid function parameters and data, the program failed, check the error code returned by the critical function, and the processing exception. Standards that require defensive programming include: erroneous input data, memory, or hard disk space is not enough, can not open a file, the external device can not access, the network connection is not or even in the program, the purpose is to maintain the operation of the program . If your program is defensive, don't forget to use assertions. If you use the assertion, don't forget the defensive programming. These two techniques are preferably used together. Second, tracking statements
1. Basic concept
Tracking statements (Trace Statements) enables the program to perform the programmer to view the variable values. They provide a program for observation and independently of an interactive debugger, but most features are commonly used to supplement the information provided by the debugger. In VC, tracking messages typically output the Debug tag in the output window, or re-output it into a file. The characteristics of the tracking statement are as follows:
Tracking statements are used to report important running events in the code.
The compilation of the tracking statement is usually conditional and only exists in the debug version, and is not compiled in the publish version.
Tracking statements cannot include program code or have indirect effects on program code.
The purpose of the tracking statement is to provide information to the programmer instead of to the user.
The tracking statement is also a debug statement, which can execute the program, and programmers can view the variables in the run. Tracking statements are very effective for programs that use interactive debuggers.
The difference between tracking statements and assertions is as follows:
The tracking statement is unconditional, assertion is a conditional Boolean statement.
The tracking statement is used to display the program execution and variable values, not directly displaying bugs, asserts to show BUG.
The tracking statement outputs the information to the debug window or file, which can be arbitrarily ignored, asserting the execution of the interrupt program.
2, tracking statement in the MFC
In MFC, you can use Trace and AFXOutputDebugstring macros, COBject :: Dump virtual functions and AFXDUMPSTACK functions. The Trace Macro is implemented by AFXDUMP, and AFXDUMP is implemented by AFXOUTPUTDEBUGSTRING. AfxoutPutDebugstring Macro and AFXDUMPSTACK functions can be compiled in all versions, others can only be compiled in debug versions.
(1) Trace macro has the following form:
_Trace (ReportType, Format);
_Trace0 (ReportType, Format, Arg1);
_Trace1 (ReportType, Format, Arg1, Arg2);
_Trace2 (ReportType, Format, Arg1, Arg2, Arg3);
_Trace3 (ReportType, Format, Arg1, Arg2, Arg3, Arg4);
In the MFC, it is recommended to use Tracen Macros. When using Trace macro, you need to use the _T macro to format parameters to properly resolve Unicode corrections, while Tracen does not need.
One disadvantage in the MFC Trace macro is that the AFXTRACE function uses a 512-character fixed size buffer, which makes it useless when tracking the long string.
(2) COBject :: DUMP
The COBJECT class has a dump (DUMP) virtual function, and all the classes of the COBJECT can output their values by overloading this function. 3, Visual C message PRAGMA
Message PRAGMA is actually a compiletable tracking statement, you can use it to warn the potential editing (Build) issues found during the pre-processing. Classic example:
#if (WinVer> = 0x0500)
#pragma Message ("NOTE: WINVER HAEN Defined as 0x0500 or Greater.")
#ENDIF
Message PRAGMA is very useful, especially in complex. However, if you want to detect a specific problem, not a potential problem, use #error pretreatment instead of interrupting compiles more directly.
Whenever you have errors in your program and you want more information, you should check the tracking message. Since the buffer of the VC output window is limited, if the speed generated by the tracking message data exceeds the speed of the output window processing, the message will be filled with the buffer, resulting in data loss. A simple way to avoid this problem is to call the Sleep API function when the code segment of the output of a large amount of data is output.
Three, abnormal
1. Basic concept
The error is a condition where additional processing is not performed, and the thread does not perform properly. An exception is used to handle errors. One obvious advantage of using an abnormality is that they can make the program code and the error handling code by issuing an error signal, and will not let the program ignore the error, and you don't have to keep check the return value of the function, so they simplify the program code . Another benefit is that they don't need a strict programming style.
Abnormal basic characteristics:
Abnormal is based on each process and processes.
Abnormal cannot be ignored by the thread, must be processed.
Unprocessed anomalies will end the process, not just end threads.
Abnormally comes to release all stack objects when the stack is released, avoiding the vulnerability of resources.
Abnormal processing requires a lot of additional operations, making it unsuitable for frequently running code.
Can throw any type of abnormal object, except for integers.
If it is performed correctly, the exception handling has the following features:
Is an exception not a normal operation result, it is a special case.
The exception is used in the case where the return value is invalid.
Violent is reliable and cannot be ignored.
Abnormally simplifies the error handling, simplifies the program code, making the error handling more convenient.
By default by Visual C , the exception is handled in the debug version, and the release is not processed in the release version. Since the exception is also an error, the Windows exception code uses a bit mapping mode as the Windows error code, which is a 32-bit value, which is defined by Microsoft, and the maximum four digits of any abnormal code are always 1100 (binary), ie 16 The 0xc in the encyclopedia.
2, Windows structural exceptions and C abnormalities
Windows structural exceptions are thrown as a hardware abnormality (such as access illegal or zero-separated) or operating system abnormal results, C exception can only be thrown by the Throw statement. Windows structural exception handling cannot handle the resolution of the object, so you should use C exceptions in the C program. However, C abnormal cannot handle hardware and operating system exceptions, and your program needs to convert structural abnormalities to C exceptions. C exceptions do not throw from your program code but throw from the C runtime, so you need to call the stack window to return your code. In order to properly handle hardware and operating system exceptions, you can create your own anomaly class and use the _SET_SE_TRANSLATOR function to install a structure exception to C exceptions, but do not capture the structural exceptions that cannot be recovered. 3, the abnormality in the MFC
In the MFC, all anomaly object is derived from the CEXCeption base class (which has a very convenient GetErrorMessage and ReportError member functions). Most MFC abnormalities are dynamically allocated, and when they are captured, they must be deleted, and the MFC exceptions that are not captured are captured and deleted in the AFXCallWndProc function.
4, abnormal overhead
When the C exception is thrown, the function call chain will go backtrack the search and find a processor that can handle such exceptions. If you didn't find it, the process ended. If found, the call stack will be released, all automatic (local) variables will also be released, and the stack will be organized as the context-related device of the exception processor. Therefore, exception overhead is an automatic variable table for an exception processor directory and an active auto variable (it requires additional code, memory, and whether it is thrown, it will run), and have to add a search and automatic variable of the function call chain. The adjustment of the stack (it only needs to be performed when throwing an exception).
5, abnormal strategy
(1) Throw a timing
The timing of throwing an exception should be a function to find an error. If there is no special operation, the error can prevent the program from running normally, and this operation is not completed, or when the function is impossible to return value.
Use exception handling easier, more reliable, more efficient, can create a more robust code. However, it should only use an abnormal handling in an accident. If you think a pointer should be null, this value is checked directly in this condition without using an exception.
(2) When will he capture?
For this issue, there are some possible standards:
When a function knows how to handle this exception.
When this function can reasonably handle this exception and advanced functions do not know how to handle it.
When throwing an exception may cause the process to crash.
When a function can continue to execute its task.
When you need to organize allocation resources.
A disadvantage of exception handling is that it may lead to the leakage of resources. Therefore, preventing resource leaks should be part of the maintenance process is safe. The stack is released automatically, and the local variable is automatically sorted, but does not include dynamically allocated variables. You can use a smart (SMART) pointer to protect your code without resource leakage without abnormalities.
(3) How to capture
Non-MFC C abnormalities should be captured by reference. Using reference capture exceptions do not need to delete an exception object (because the exceptions that use reference captures will be transmitted in the stack), and it retains polymorphism (so you captured the exception object is the exception object you thrown).
. MFC abnormality should be captured by a pointer. Use pointer to capture exceptions require you to delete objects. Because they are usually allocated from the heap, when you process anomalies, you need to call the DELETE member function to delete. You can't use the omission capture processor to capture the MFC exception, which will cause a memory leak. You must use the DELETE member function to delete the MFC exception without delete because some MFC exceptions are created for static objects. Throw an exception during the release of the stack causes the process to terminate the process. The release stack involves calling the destructor, an exception can prevent calling the Delete operator, which will have resource leaks, so the exception is preferably not thrown from the destructive function. If you want to throw an abnormality in the destructive function, you must handle it to avoid resource leakage.
6, abnormal and defensive programming
Continue to execute procedures during an abnormality, which is important than performing a normal shutdown action. If possible, you should focus on continuing programs and close the program normally in a must-have. Maybe the most fundamental normal shutdown is a process that can restart your own when you crash, which is a technology used by the Windows Explorer.
If a C exception associated with an error is expected, if it occurs in the code of the non-critical, if it does not occur in the result of the program startup or end or an unrecoverable structure, this program can be Restore it from it.
Once your program can recover from an error related to the error, you should check the status of the program and its documentation. If the program and document have been destroyed, the process should also be terminated. Otherwise, the program needs to notify the client to determine the process of action. If the client agrees to execute, the program should recover errors and proceed.
Fourth, return value
Not in the case, the exception can be used, as in the use of Windows API programming or with COM programming, it is not used. When an exception is not suitable, use the return value is a good way.
Basic features of the return value:
The return value can indicate that the normal and abnormal functions are running, but the thread will continue to run.
The return value is easily ignored.
The return value is an integer in a typical case, typically maps that conforming to a predefined value.
The return value can transmit and receive efficiently.
Therefore, the return value is most suitable for use in the following:
. Status information for non-error
In most cases, it can be ignored freely without problems.
For more prone to errors in the cycle.
.
Used in intermediate language modules such as
COM
Errors in components.