Big talk debugger (Part 1)

Source: Internet
Author: User
Collation

Writing a program is always based on certain assumptions or prerequisites. Errors are often caused by hypothetical errors,
Therefore, when an error occurs, you need to track the context of each piece. In terms of the problem, the debugger is a human
.

I remember that when I first entered the school, many students couldn't even distinguish between C and MSVC, so the debugger should not be mentioned. In fact, I don't think
Using a debugger will cause a big loss. Skillful Use of the debugger can not only avoid unnecessary labor, but also
Analysis Program Execution to obtain or verify a lot of detailed knowledge.

It is necessary to talk about the debugger first. At least be able to know what it actually does to the program to avoid unnecessary
. It also makes it no longer so mysterious :)

1. breakpoint

The main function of the debugger is the execution of the control program. This function is implemented through hardware breakpoints. Therefore
The combination of CPU.

The specific process is as follows:
(1) assume that the debugger needs to interrupt program execution at the Address of the program Address space, it must be at the Address
Write a breakpoint command "int 3" (0xCC), of course, to save the byte to be overwritten;
(2) then let the program execute at full speed until it reaches the Address location. At this time, the interruption on the third (breakpoint interruption) is triggered ),
As a result, the debugger obtains control (by taking over the interrupt on the 3 th in advance), and naturally obtains the CPU execution right;
(3) When the user finishes processing and needs to continue the execution, the debugger writes back the previously overwritten instruction bytes and opens the CPU
And then resume the execution of the program;
(4) After the program executes a command, because the CPU is in the single-step status, it will automatically trigger the 5th interruption (in a single step
). At this time, the debugger (by taking over the interrupt on the 5 th in advance) obtains the CPU again, and then writes back the interrupt at the Address.
Command.

It is shown in the flowchart as follows:
---------------------------------
| Write breakpoint | --> | execution program | -- INT 3 --> | restore code | --
----------- |
-----------------------------------------------------------
| ------------------------------------
-> | User operation | --> | set the single-step flag | --> | execution program |-int 5-
----------- -------------- ----------- |
-----------------------------------------------------------
| -----------
-> | Write-back breakpoint | --> ......
-----------

This is the most basic workflow of the debugger, and almost all other functions are based on this form. For example, in the call command
"Step Over", the reproducer needs to calculate the address of the next instruction, and then write the breakpoint there,
To complete the process-level single-step execution.

2. Stack Traversal

This is also a task that must be completed by the debugger and must be done by the compiler.
Generally, the compiler inserts the code at the beginning of each function:

Push ebp
Mov ebp, esp

Stack frame. During function execution, the value pushed into the stack and the value of EBP will not change.
This is equivalent to the use of the debugger: the debugger obtains the return address for calling the current function as long as ebp + 4 is interfaced.
The Inter-address ebp can obtain the ebp pushed by "push ebp" at the beginning of the called function. So ebp '= [ebp
], Then [ebp '+ 4] is the return address of the function that calls the current function.

In A simple example, assume that A calls B, B calls C again, and goes through the stack traversal in C. The stack is
Format:

ESP ----> ---------------
| Automatic Variable Area of C |
EBP ----> ---------------
| EBP | ---------------
| Return address of B | <-- B calls C
---------------
| Call C parameters |
---------------
| Automatic Variable Area of B |
---------------
| EBP | <-- ebp in a; ebp at the beginning of B.
---------------
| Return address of A | <-- A calls B
---------------
| Call parameters of B |
---------------
| Automatic Variable Area of A |
---------------

After clarifying the truth, you can write the following code to traverse the stack:

Int main (int argc, char * argv [])
{
Long e;
_ Asm mov e, ebp;/* obtain EBP */
While (e)
{
Printf ("% 08X/n", * (long *) (e + 4);/* [EBP + 4] indicates the return address */
E = * (long *) e;/* [EBP] is the EBP in the call function */
}
Return 0;
}

From the running result of this applet, we can see that the return address of main is 00401129 h (different compiling environments may
). This is actually the C Runtime Library calling main.

In fact, when the compiler optimization function is enabled, the compiler may no longer create stack frames for some functions, so the stack
Traversal is no longer feasible. However, you can use the toggle to tell the compiler not to ignore the stack frame.

3. debugging symbols

The debugging symbol is like this: it converts the address to the number of lines in the source code or to the name of the function,
Or the name of the variable. It can also convert the latter into the former. Symbol-level debugging is based on debugging symbols.
.

Obviously, debugging symbols are self-evident in the debugger. It cannot be generated by the debugger and can only be generated by the compiler at compile time.
External embedding. The formats of debugging symbols generated by various compilers are different. For example, MSVC adopts the PDB format, while GC
C adopts STABS, DWARF, COFF, and other formats.

PDB (Program Database) is a debugging symbol used on MSVC and. NET platforms. Its History can be traced back to MS.
In the C7 era. PDB is a highly descriptive format that can contain source code file names, source code lines,
Variable address, process address, and other useful data; MSVC6 and later compilers use PDB to support "Edit &
Continue "is a fancy feature :)

Through a PDB file, you can understand the outline of the program. However, the PDB format is updated frequently
Generally, you can only use dbghelp. dll provided by WinDBG to access PDB.
. However, after MSVC7, MS published a set of things called DIA, which can read data from PDB.
And with the update of the PDB format, DIA is also updated; but this can only be used in MSVC7 or later versions, the new version of the MSDN
Library.

Debugging symbols will be discussed later.

The three points above are essential technologies for each symbolic debugger. Although the principle is simple, the actual operation is
Not that easy. For example, multi-thread debugging, real-time processing of dynamic libraries, and Exception Handling of programs are supported,
Integrate user operations ...... However, these are the work of others, and we just need to enjoy it :)

Starting from this article, MSVC6 is used as the discussion object.

I. debugging preparation

1. Compiler

By specifying the "Debug" Compilation mode: "Build-> Set Active Configuration", you can ensure that
Supports symbol debugging.

However, there is one thing to be clarified here: Although there are "Debug" and "Release" compilation methods, as a compiler, it is
There is no such concept. The compilation methods of "Debug" and "Release" are only combined by different compiler switches.
. Therefore, it is also feasible to debug the symbols of a program compiled with "Release.
For debugging-related switches, Run "cl -? "You can see.

2. system debugging Operator

No C program runs without the support of the Runtime Library; platform-related programs require direct system calls.
. This has a problem: if an error occurs in the system process, how can we get the system-level symbol to track
Unified Call process? There are two solutions.

One is to install the system debugging character in "Diagnosis Tools" released by both MS and the operating system.
A system debug character is a debugging symbol generated when Windows is compiled. There is a lot of information, including the stack time
The address of the function to be used; there are some undisclosed global variables (for example, GDI32.dll has a very famous
Does not disclose the global volume) and process. With these system debugging characters, you can easily obtain the context of the system call.

However, the system debug character has a serious disadvantage: each system file corresponds to a system debug character, and both versions are required.
Must be completely consistent before use. Any system update operations (such as Service Pack or vulnerability patches)
It will make the corresponding debugging operator ineffective unless it is updated to a new debugging operator in time. Therefore, debugging is inconvenient.
. We recommend that you do not use a system debug character if you do not perform kernel debugging (the system debug character is the best choice at this time.

The other is to dynamically scan the export table of the system module.
This method requires the debugger to be able to scan all the exported
Function address, and insert your own symbol table. It can be seen that this method is time-consuming, but it is the most convenient to use.
.

MSVC supports this technology: "Tools-> Options-> Debug". You can see "Load COFF & Exports" in the lower left corner.
? Select it to enable it. MSVC is not selected by default (I really don't know what MS people think ......).

Ii. Start debugging

There are two ways to debug an application. One is to start the program by the debugger; the other is to start the program first,
Then, append the debugger to it at a certain time.

The latter method is generally used when an application error occurs or you do not want to restart the program. You only need to use "Build-
> Start Debug-> Attach to Process ", you can select according to the application PID (Process identifier.

In normal development, debugging is generally started through the first method: "Build-> Start Debug-> Go", or directly
Press F5.

In addition to F5, there are two ways to start, one is "Step Into" (F11), and the other is "Run
Cursor "(Ctrl + F10 ). The former automatically stops at the first statement of the main function after the debugger is started, and the latter stops
Execute the statement where the cursor is located and interrupt the operation (for example, I am a friend of mine :)).

Iii. debugging window

After Debugging starts, the MSVC interface is changed to display the debugging-related window. These important windows include
: Output, Watch, Call Stack, Memory, Variables, Registers, and Disassembly. Pass"
Views-> Debug Windows "can display or hide them.

1. Output (Alt + 2)

The Output window is a multi-purpose window, and debugging messages are not displayed. Here we are talking about the corresponding Debug labels.
Column.
It is used to display the feedback message of the debugger or the message that the application actively outputs to the debugger (which will be mentioned later ).

Two types of Output feedback messages are worth noting.

The first is the loading of the notification module symbols. If there is no debug character available, there will be a similar "no" in the Output
Matching symbolic information found. This requires two methods in "debugging Preparation ".
Add a symbol (if both are used, the first is preferred ). If the second type is used, the message will become "Load
Ed exports for xxx. dll ".

The second is the return value at the end of the process. Output is the only window that will not be automatically closed after debugging.
It will display the return value (32-bit unsigned integer) at the end of the program process ). Some tool programs are not displayed when an error occurs
Error information, but returns a non-zero value to the operating system to indicate the cause. In this case
The return value is displayed in the t window.

2. Watch

The Watch window is the most important window in the symbolic debugging process. Watch can be used freely when symbols are available
View the values of almost all legal expressions in C Language (these expressions can contain standard operators or variables)
, Functions, etc.); you can even use the Watch window to convert the type or execute a program!
You can think of the Watch window as a compiler, but it can only process expressions.
The tester directly depends on the compiler ).

Pay attention to the bottom of the Watch window. There are 4 tags in total, so you can divide the expressions to be monitored into four categories to facilitate
.

For example (do not input quotation marks into Watch ^ ):
"A": displays the value of variable;
"& A": displays the address of;
"* (Unsigned char *) 0x400000": displays the value of a byte at the memory position of H;
"Func ()": Call process func (if any ).
"A = 3": Assign 2 to.

Watch has some very powerful special usage, the third article specifically described.

3. Call Stack

The "Principle" section describes the stack traversal algorithm. In fact, stack display requires the participation of debugging symbols. Debug party
Compiled programs can clearly display the calling process of the Call Stack.
Follow one of the two methods in "debugging Preparation" to tell the debugger how to obtain the debugging token ).

Double-click a layer.

The right-click menu on the Call Stack has many good functions. For example, right-click a layer in the stack and select "Run
To Cursor ", the program will be interrupted until the function of this layer ends the call to the previous layer.

4. Memory & Registers

Memory is used to check the Memory;
Registers is used to view Registers.

There is nothing to say about these two windows. But pay attention to the following two points:

One is that the Memory Window not only accepts a 32-bit unsigned integer as the address, but also accepts an expression
Address (it can still contain the currently visible variables); however, its interpretation of the expression is somewhat different from that of the Watch window:
If you enter "a", it will be displayed from the address of a. If you enter "a + 3", it will first calculate a + 3 with the current value of,
Then, use the result as the address to display it from there;

The second is that the EAX value of Registers is the most noteworthy, because the return value of the function is usually stored through EAX.
. After a function is executed, you only need to check its return values (if any) in the debugger.
Check EAX.

In addition, the identity Registers in Registers are decomposed and displayed:
OV: overflow mark; UP: direction mark; EI: interrupt start mark; PL: symbol mark (whether the result is positive or negative );
ZR: zero mark (whether the result is 0); AC: Secondary carry mark; PE: parity mark; CF: Carry mark.

5. Disassembly (Alt + 8)

MSVC disassembly windows are mostly used. They can display source code, assembly code, and machine code at the same time. Shortcut menu
There is a option to control the display.

Disassembly has a unique function: Right-click a code and select "Set Next Statement ".
Directly modify the IP address to make it the next command to be executed. This is as free as goto.

Note: This function only appears in the shortcut menu of the Disassembly window. It is not found anywhere else.

Iv. debugging Control

To immediately interrupt the execution of a running program for debugging, you only need to "Build-> Break ".
. The problem of multi-thread switching will be mentioned later.

MSVC has many ways for users to control program execution. For example, in the Disassembly window, "goto" is
Type. In addition, "Step Into", "Step Over", "Step Out", and "Run to Cursor" are common examples.
. They are all in the Build menu.

First, you must note that, as a debugger, it determines the meaning of user operations based on the activated window type. Pair
In the source code window, all operations are completed at the source code level; for the Disassembly window, all operations are collected
The encoding level is complete.

"Step Into" (F11): In the first sense, it is a statement by statement (here the statement is the statement in the Code, for example, "a = 3
; ", Etc.); in the second sense, the command is executed by (CPU;

"Step Over" (F10): In the first sense, it is executed by function (such as the function defined in the source code );
In the two meanings, it is a process-by-process execution (in fact, when a call is encountered, it is not tracked, but directly executed to the call.
A command is interrupted ).

The difference between the two lies in that when a function (process) is encountered, the former will track in, while the latter will regard the function as a "command" and
Skip.

"Step Out" (Shift + F11): In the first sense, it is executed to the nearest return address in the stack (that is
In the second sense, it is to execute the current process. The next point of the last call command
Interrupt.

"Run to Cursor": it is interrupted when the current Cursor is running.

V. Terminate debugging

To terminate one Debugging and return to the editing status, "Build-> Stop Debugging" (Shift + F5 );
To Restart immediately after the termination (this is often because the execution is not properly controlled and beyond the target), "Build-> Restart
"(Ctrl + Shift + F5 ).

Vi. breakpoint settings

The simplest breakpoint is the position breakpoint: move the cursor to the source code line to be interrupted, and press F9 to set
Set or cancel the breakpoint.

All Breakpoints can be managed in the "Edit-> Breakpoints" (Alt + F9) dialog box. Here you can set more
Multiple complex breakpoints.

1. Conditional breakpoint

Select the breakpoint to be modified, and press the Condition button to set the conditions for interruption at the breakpoint.
Note that the Expression here is a C language Expression. variables can be used, but if the Expression does not exist
The debugger will disable the breakpoint.

2. Data breakpoint

This is a type of strong breakpoint. It does not have a fixed position and only requires one expression. interruption occurs only when the expression is
When the result is true. For example, if the expression "argc = 3" is entered, as long as argc is assigned
3, it will cause interruption.

This function is provided by the CPU, and does not rely on the debugger to execute code in one step while checking the expression :)

3. Window message breakpoint

I know little about GUI programs. If you want to use it, try it more by yourself :)

This article focuses on some tips to speed up the debugging process.

1. Fast debugging

On a Win2000 or later system, you can immediately press F12 for any program that is being debugged (but has not been interrupted ).
Interrupt this program for debugging. Just like making the debugger Break.

Ii. Context of the program

After the program has been interrupted, you can use "Debug-> Threads" to select the thread to be followed in multi-thread debugging.
Or manage the thread status. "Debug-> Modules" to view the distribution of Modules in the program address space.

In addition, pay attention to the upper part of the Variables debugging window, which can also be used to quickly switch the context of function calls.

Iii. Exception management

Familiar with the debugger's exception handling process, which is good for debugging code with exception handling. I have not figured out these before
It is inconvenient for me to comment on things.

You can use "Debug-> Exceptions" to set the action of the debugger on Exceptions.
At the debugger level, there are two types of exception handling: "Stop always" and "Stop if
Not handled ". The following describes the differences between the two.
Exceptions are reported to the debugger in a unified format. When an exception is triggered for the first time: the debugger can immediately stop the process
This is "Stop always". The debugger can also start the operating system to handle exceptions (for example, _ try /_
If the program has no code to handle the exception, the operating system reports the exception to the debugger again.
In this case, the debugger is interrupted. This is "Stop if not handled ".

(Due to the "Stop always" option) The First interruption, MSVC will prompt "First-Chance ";
The program does not process the Exception Code and causes the second interruption. MSVC will prompt "Unhandled ".

For example, the following code is provided:
Int main (void)
{
Int a = 0;
_ Try
{
A/=;
}
_ Partition T (1)
{
Printf ("divided by zero! ");
}
Return 0;
}
The two methods to handle the zero division exception affect whether the debugger is interrupted at "A/=.

If it is set to "stop always", the exception is triggered. After it is executed again, the debugger will ask the user whether
The exception is passed to the program. That is, whether to expand the program exception handling code from the line to handle the exception. Select "no"
Then, the debugger will not use the Exception Processing code of the program, but will continue to execute the program.

Here, "Continue execution" has two meanings: one is to re-Execute from the breakpoint, and the other is to re-Execute from the next breakpoint
Command. This depends on the exception handling command (the parameter in _ handle t) and the exception type. It will not be used here
.

The entire process can be shown in a flowchart:
|
| Exception!
|
-------------- N ------------------- y ----------
| Stop always? | --- + ---> | Does the program handle exceptions? | ---> | Exception Handling |
-------------- | -----------------------------
Y | n |
-------------- |
| Interrupt program execution |
-------------- |
| ^ |
-------------- ^ -------------- |
| User operation |
-------------- |
|
------------------- |
| Is an exception passed to the program? |-Y |
------------------- |
N |
-------------- |
| Continue execution | <----------------- + ----------------------
--------------
|
|


4. Special commands for the Watch window

Although the Watch window supports almost all C expressions flexibly, it is sometimes inconvenient. To be efficient
When you use the Watch window, you must remember some special usage.

1. Monitor System calls

Programmers on Windows must be familiar with the GetLastError system process. GetLastError uses a global
Volume records the success mark or cause of failure after the last system call.

Enter "@ err" in the Watch window, and the returned value of GetLastError is displayed (32-bit unsigned integer)
.
For example, if CreateFile is called to open a non-existent file, after CreateFile is returned, "@ e
Rr "will display" 2 ".

2. Error Code Translation

The suffix ", hr" can be used to implement the "Error Lookup" tool. It translates an integer into an explanation.
Cause text. For example, "3, hr", "0x00000003 system cannot find the specified path" is displayed ".

The best use of the hr suffix is @ err. For example, for the failed file opening operation, "@ err, hr" will display "0x000
00002 the system cannot find the specified file ". It is very convenient to locate the cause of the error.

3. numeric format

Watch has the default display in hexadecimal format. You can choose from the shortcut menu in the Watch window.
Select. You can add a suffix to specify the display format. Note that the difference is large.
In lower case.

C: displays the data according to ASCII characters;
X or X: displays in the unsigned hexadecimal format;
D: Display in signed decimal format;
U: Display in unsigned decimal format;
O: Display according to the unsigned octal chart;

There are also two modifiers (must match the above suffix ):
L: 32-bit display;
H: Display by 16 bits.

Example:
65, c: Display 'a ';
0x12345678, d: Display 305419396;
0x12345678, hx: 0x5678.

Watch also supports floating point display:

No suffix specified: Double precision;
F: displays the information according to the accuracy of the signed ticket;
E: Display by scientific notation;
G: select a shorter display;

Example:
1./3: Display 0.33333333333333;
1./3, f: 0x333333

4. string format

It is worth noting that Unicode strings are displayed. It has the following suffixes:

S: Display by ANSI string;
Su: Display by Unicode string.

5. memory image

In fact, this is to complete the Memory window function. However, it does not have the disadvantages of the Memory Window: for example, each time only
Display from an address (because the Memory window is one), cannot be formatted, and so on.
Add a suffix to the Watch window to specify the display format.

Ma: 64 bytes are displayed consecutively with ASCII characters;
Mb or m: 16 bytes are displayed in the byte format, and then the 16 bytes are continuously displayed with ASCII characters;
Mw: displays 8 words (16 digits) consecutively );
Md: displays four double characters (32 characters) consecutively );
Mq: displays two four-digit characters (64-bit) consecutively );
Mu: displays 8 characters in a row, and then displays the 8 characters in a row with Unicode characters;

For example:
0x400000, MW: 0x00400000 5a4d 0090 0003 0000 0004 FFFF 0000
0x400000, MQ: 0x00400000 running 000300905a4d running ffff00000004

6. Array Display

This is an important feature. Since C language does not distinguish between pointers and arrays in function declaration-for example, "int func (int
There is no difference between a [100]) "and" int func (int * A) "-So an array is used to call
In the process of executing the function, the watch window only treats it as a pointer, so only the first one can be displayed.
Element. This is fundamentally caused by the compiler.

The Watch window supports adding a number after the array name to indicate that this is an array and Its width (number of elements) has
. For example, "a, 100": expand this item and you can see a [0] to a [99].

7. Others

WM: The Windows message code is displayed in a macro;
For example: 0x0010, WM: Display wm_close; extremely useful in the debugging window;

Pseudo timer @ CLK:
@ CLK is used to display a 32-bit unsigned integer. This integer is related to time and can be used as a simple timer.

In addition, it is important to master the shortcut keys of Common commands to speed up debugging ~~~).
Please refer to the relevant documentation :)

The first two articles introduce the basic usage of the msvc debugger. This article does not focus on the debugger, but on code compilation.
Write down and describe some methods that can actively cooperate with debugging.

I. outputdebugstring & afxdump

OutputDebugString is a function provided by Windows. It accepts a string and
Special debugging events-passed to the debugger.

From the program perspective, if the program is not debugged, the function call has no effect. However, when the debugger exists
The debugger can get this string. For example, the program is debugged by MSVC and OutputDebugString is called,
This string is displayed in the Debug column of the MSVC Output window.

It has the following advantages:
1. It is suitable for analysis of program processes and does not need to interrupt the program once and again to view variables;
2. Suitable for debugging code related to the interface, because interruptions to the program may affect the interface of the Program (because
For the debugger itself, there is also a GUI, so it will block and so on), and it cannot achieve the expected debugging. OutputDebugSt
Ring does not have this disadvantage;
3. Suitable for debugging non-console programs. This type of program does not have a standard output device, so printf functions cannot be used, only
Can use OutputDebugString;

MFC has a global afxDump volume to wrap OutputDebugString.
For example, "afxDump <56 <str" is easier to use.

Ii. Macro _ DEBUG

_ DEBUG macro is used to indicate whether the current compilation is in Debug mode or Release mode. As stated at the beginning of article 2
: The Compiler does not distinguish Debug from Release.
To write a piece of code that can be processed differently in two modes, MSVC helps us define this macro (of course
You can also define another macro by using the compiler switch-D ).

For example, you can run the following code:
# Ifdef _ DEBUG
Printf ("a = % d/n", );
# Endif

In Debug mode, the code in the middle line can be executed. In Release mode, the compiler cannot see it at all.
This sentence. Therefore, embedding the code that assists debugging in this form in the code will not increase the release cost.

3. Macro _ FILE __,__ LINE __

These two are macros maintained by the compiler. _ FILE _ indicates the name of the currently compiled FILE, __line _ indicates that the FILE is being
The number of lines of compiled code in the file.
These two macros are very important. They are the implementation basis of assert (because assert will report when the assert fails
Wrong file name and number of lines) is also a good debugging method that programmers can use.

Consider the following code:
Void error (char * s ){
Printf ("error-% s/n", s );
Exit (-1 );
}
This type of code is frequently used and can be used to handle the same errors in different places of the program.
But once an error occurs, how can we determine where the error was called? This has to be in error again.
Set breakpoints, execute them again, and use the stack traversal function of the debugger to confirm.

In fact, using the two macros above can avoid enabling the debugger. Modify the code:
# Define error (s )/
{Printf ("error-% s @ file: % s line % d/n", s ,__ FILE __,__ LINE __);/
Exit (-1 );}

The error file name and number of lines can be seen from the error message immediately, without the need for a debugger. This is not more convenient
?

Iv. Preprocessing command # Line

# Line is opposite to _ line _ and _ file. The latter is used to obtain the current row or file name, while the former is used to set the current row.
Number or file name.
If the latter two are regarded as global variables, # line 100 "XYZ. L" is equivalent to _ line __= 100 and _ file __
= "XYZ. L ".

# Line is useful in some scenarios, such as in code generators. Taking the syntax analyzer's generator flex as an example, FL
Ex scans a syntax file with specific syntax and generates a c file as a syntax analyzer.
Anyone who has used flex knows that sometimes code needs to be embedded in flex. The code will be stored in the generated C file by Flex.
.
The problem arises: the compiler can compile only C files generated, so when an error occurs in the embedded code, the debugger can only
Locate in the C file. Generally, the size of this c file is spectacular, and it is difficult to analyze it.
So we hope that the debugger can actively locate it in the initial syntax file. At this time, # Line is the best choice.

For example, you can run the following code:
Int main ()
{
Int A = 0;
# Line 1
A/=;
Return 0;
}
Compile and start the debugger to see where the debugger went when a/= A went wrong :)

5. Assert)

The assert function is specially used for debugging and defined in assert. h.
Assert accepts a value. If it is true, no action is taken. Otherwise, a dialog box appears asking users to select "Ignore ",
"Debug" or "Abort ".

Assert is used for prerequisite detection and is the most effective method to avoid errors. Assert is set under release Compilation
The value is (void) 0. Obviously, assert does not increase the program cost during release.

For example:
Assert (A = B );
If it is compiled in debug mode, when this sentence is executed, if! = B, it will immediately lead to interruption;
If this statement is not compiled in the release mode.

Assert can simulate conditional breakpoints, such:
Assert (! (A = B) interrupt when a = B (it is more convenient to write a macro ).
This avoids the use of the debugger's conditional breakpoint (otherwise it is too troublesome to set in the breakpoints dialog box ).

For example:
Assert (0 );
This is a breakpoint that must fail and is often used in code analysis.

The syntax of assert is simple. Although easy to use, there are also various techniques in it. A profound and profound letter
Number.
The most exaggerated usage I have ever seen is:
Assert (! "Never come here! ");

Do you understand? This is also a breakpoint that must fail. This is from John, an important character of numbench.
Robbins. It can be seen that this person is too lazy to be surprised, and even comments are put in assert ......

Vi. Others

1. rtti

Rtti is the runtime type recognition and can be used to detect the type of A Class Object.
For example, A function accepts A parameter of type A (this is A class type. Obviously, as long as the class inherited from
All types can be passed. However, if you expect this function to not accept a derived type, it is more convenient to use RTTI with assert.
.

2. ASSERT_KINDOF, ASSERT_VALID, etc.

(Type) Assertions based on MFC. There are also various variants with strong functions, but they can only be used in MFC programs.

For more information, see the relevant documentation.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.