Debugging Basics: Breakpoints
This topic applies to:
Pro, Premium, and Ultimate
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 stop or end the execution of your program; execution can be resumed at any time.
You can think of break mode as being like a time-out. All the elements remain (functions, variables, and objects remain in memory, for example), but their movements and activities are suspended. During break mode, you can examine the elements' positions and states to look for violations or bugs. You can also make adjustments to the program while in break mode; for example, you can change the value of a variable. You can move the execution point, which changes the statement that will be executed next when execution resumes. In C++, C#, and Visual Basic, you can even change the code itself while in break mode by using a powerful feature called Edit and Continue.
Breakpoints provide a powerful tool that enables 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, and then start to debug. This speeds up the debugging process. Without this ability, it would be almost impossible to debug a large program.
Many programming languages have statements or constructs that suspend execution and put your program into break mode. For example, Visual Basic 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 must manually remove those Stop statements before you build the release version, or you must use conditionals, as shown here:
#If DEBUG Then Stop #End If
If you want to temporarily disable a Stop statement, you must locate the statement in your source code and comment it out:
This is no problem if you only have one Stop statement. However, if you are debugging a large program that has lots of Stop statements, searching for all of the statements and commenting each one out can be time-consuming. By using 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, 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 code only. A data breakpoint is set on a global or local variable, instead of a location in the code. Setting a data breakpoint causes execution to break when the value of that variable changes.
To provide even more flexibility, the Visual Studio debugger enables you to set properties that modify the behavior of a breakpoint:
Hit count enables you to determine how many times the breakpoint is hit before the debugger breaks execution. By default, the debugger breaks execution every time that 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, or 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 appear until the 100th or 1000th iteration. To debug such a problem, you can set a breakpoint with a hit count of 100 or 1000.
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. For example, suppose you are debugging a banking program where the account balance is never allowed to go below zero. You might set breakpoints at certain locations in the code and attach a condition such as balance < 0 to 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, and then continue execution to the second breakpoint location, and so on.
Action specifies something that should occur when the breakpoint is hit. By default, the debugger breaks execution, but you can choose to print a message or run a Visual Studio macro instead. If you decide to print a message instead of breaking, the breakpoint has an effect very similar to a Trace statement. This method of using breakpoints is called tracepoints.
Filter lets you specify a process or thread for the breakpoint.
One especially useful technique is setting breakpoints in the Call Stack window. By 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 a previous call that has not yet returned. The debugger will encounter that breakpoint and break execution on the way out of the current calls.