Debugging Basics: Breakpoints
A breakpoint is a signal that tells the debugger to temporarily suspend execution of your program at a certain point. When execution is suspended at a breakpoint, your program is said to be in break mode. Entering break mode does not terminate or end the execution of your program. Execution can be resumed (continued) at any time.
You can think of break mode as being like a timeout at sporting event. All the players remain on the field (functions, variables, and objects remain in memory), but their movements and activities are suspended. During the timeout, the referee (that's you) can examine their positions and states to look for violations (bugs). The referee has the power to make adjustments to the players during the timeout. You have the power to make adjustments to the program while in break mode. You can changes the value of a variable, for example. You can move the execution point, which changes the statement that will be executed next when execution resumes. In C++, you can even make changes to the code itself while in break mode (a powerful feature called Edit and Continue).
Breakpoints provide a powerful tool that allows you to suspend execution where and when you need to. Rather than stepping through your code line-by-line or instruction-by-instruction, you can allow your program to run until it hits a breakpoint, then start to debug. This speeds up the debugging process enormously. Without this ability, it would be virtually impossible to debug a large program.
Many program languages have statements or constructs that suspend execution and put your program into break mode. Visual Basic, for example, has the Stop statement. Breakpoints differ from these statements because breakpoints are not actual source code that has to be added to your program. You do not type a breakpoint statement into a source window. You request a breakpoint through the debugger interface, and the debugger sets it for you. To insert a line breakpoint, click in the gray margin next to the line where you want to set the breakpoint. More complex breakpoints can be handled through a full-featured Breakpoints window.
Breakpoints have many advantages over debugging constructs such as the Visual Basic Stop statement. Breakpoints can be deleted or changed without having to change your program's source code. Because breakpoints are not statements, they never produce any extra code when you build a release version of your program. If you use Stop statements in your program, you need to manually remove the Stop statements before building the release version, or use conditionals (as show here):
#If DEBUG Then Stop #End If
If you want to disable a Stop statement temporarily, you need to locate the statement in your source code and comment it out:
This is no problem if you only have one Stop statement. If you are debugging a large program with lots of Stop statements, however, searching for all of the statements and commenting each one out can be time consuming. With breakpoints, you can select and disable or enable any or all of your breakpoints from the Breakpoints window.
Finally, breakpoints have a big advantage over Stop statements in their flexibility. A Stop statement causes execution to break on the source line where the statement is located. You can set a breakpoint on a source line that does the same thing. Alternatively, however, you can also set a breakpoint on a function or a memory address, which cannot be done with Stop statements. In addition to these location breakpoints, the Visual Studio debugger offers data breakpoints (for native C/C++ only). A data breakpoint is set on a global or local variable, rather than a location in the code. Setting a data breakpoint causes execution to break when the value of that variable changes.
To provide even greater flexibility, the Visual Studio debugger allows you to set two properties that modify the behavior of a breakpoint:
- The Hit Count allows you to determine how many times the breakpoint is hit before the debugger breaks execution. By default, the debugger breaks execution every time the breakpoint is hit. You can set a hit count to tell the debugger to break every two times the breakpoint is hit, or every 10 times, or every 512 times — any number you choose. Hit counts can be useful because some bugs do not appear the first time your program executes a loop, calls a function, or accesses a variable. Sometimes, the bug might not show up until the 100th or 1000th iteration. To debug such a problem, you can set a breakpoint with a hit count of 100 or 1000.
- The Condition is an expression that determines whether the breakpoint is hit or skipped. When the debugger reaches the breakpoint, it will evaluate the condition. The breakpoint will be hit only if the condition is satisfied. You can use a condition with a location breakpoint to stop at a specified location only when a certain condition is true. Suppose you are debugging a banking program, for example, where the account balance is never allowed to go below zero. You might set breakpoints at certain locations in the code and attach condition like
balance < 0to each one. When you run the program, execution will break at those locations only when the balance is less than zero. You can examine variables and program state at the first breakpoint location, then continue execution to the second breakpoint location, and so on.
Tip One particularly useful technique is setting breakpoints in the Call Stack Window. Using the Call Stack window, you can set a breakpoint on a particular function call. This can be especially useful when you are debugging a recursive function (a function that calls itself). If you break execution after a certain number of calls, you can use the Call Stack window to set a breakpoint on one of the previous calls that has not yet returned. The debugger will encounter that breakpoint and break execution on the way out of the current calls.