找回密码
 申请新用户
搜索
热搜: 活动 交友 discuz
查看: 6173|回复: 0

Visual C++ .NET Debugger Tutorial

[复制链接]
发表于 2008-9-1 15:23:18 | 显示全部楼层 |阅读模式
转自:http://www.cs.uvm.edu/~upe/resources/debugging/visualStudioCDebug

Contents


[size=+1]This Tutorial
This tutorial demonstrates how to use the debugging tools in Visual Studio .NET to find and fix problems in your programs. It is designed for people for who have never used a debugger before, but it may be useful for anyone who hasn't used the debugging tools in this particular software before. You should already have some knowledge of C++ and Visual Studio .NET, but the examples used for demonstration purposes are very simple. These tools can be used with programs of any size.

[size=+1]Introduction
Any debugger (whether in Visual Studio, in some other IDE, or a stand-alone program) will provide two basic functions to help you fix your code:
  • Trace Execution: You can execute one line of your program at a time, so you'll be able to see exactly where a problem occurs.
  • Watch Variables: As you trace through your program, you can monitor your variables as they get changed (so you can identify the source of bad data right away).
A variety of tools are available in Visual Studio to help you accomplish these two things (and perhaps a few more that are more subtle). We'll start by looking at the most essential tools.

[size=+1]Types of Errors
Before we begin, it's important to distinguish between two different types of errors you can have in a program. Visual Studio's compiler identifies some problems as soon as you try to run your program, and presents these in the "Output" window at the bottom of the screen:

[size=-1]A Compiler Error

These errors are almost always easy to repair. The error shown above can be fixed by declaring the 'z' variable with the appropriate type. The compiler tells you what the problem is and where it occurs in your program, so the only thing you need to know is what you had in mind when you wrote that statement.

The second type of error is the kind that appears while your program is running. You may get an exception that identifies a specific problem (such as "Null Pointer Exception") or you may just see something that isn't working the way you want. Finding these problems can be very tricky, but the debugger lets you see your program in a different way, and that can make even these obscure problems easy to fix.

[size=+1]A Buggy Program
Let's start by looking at a simple program that has a simple bug. Spider is a program that's supposed to determine whether two numbers provided by the user are equal. This program "compiles clean" (no errors, no warnings) but it does not behave as expected. Here's an example of what it does:

[size=-1]Sample Run of Spider

Clearly there is something wrong with this program, even though it compiled without any trouble. The program is reporting that 1 and 3 are equal!

The code for Spider is below. Start a new Visual Studio project and add this code in a new file (copy it from here and just pate it into an empty file). Try running the program yourself. Even if you can identify a bug just by looking, don't change anything yet. This is a deliberately simple example, but if this small piece of code were part of a larger program the errors wouldn't be as easy to find.

[size=-1]spider.cpp [size=-1](Open in new window)

[size=+1]Breakpoints
The first thing we want to do in our general debugging strategy is identify which part of the program we think is responsible for the problem. If you have absolutely no idea, you can just start at the beginning of main(). Usually you have some idea of what code may be responsible.

Once you know where you want to start debugging, put a breakpoint there. You can do this by clicking in the gray margin next to a line of code, or pressing F9 while on that line. (Note that there are many ways to activate most debugger functions, but only one or two will be presented here for each command.)

In this case let's start just before the user enters the two numbers.

[size=-1]A Breakpoint

The visual effect is obvious: a red dot appears in the margin, and the line is highlighted in red. The meaning is that whenever the program reaches this line of code in the debugger, everything will stop and you'll be able to look at the details. It's a simple concept, but it's what makes this such a powerful problem-solving tool.

[size=+1]Starting the Debugger
Visual Studio lets you run your program by pressing Ctrl+F5 (or clicking "Start Without Debugging" in the "Debug" menu), but it treats Debug mode as the default. This may cause some frustration as you start setting up breakpoints so you may want to get in the habit of using Ctrl+F5 unless you specifically want to use the debugger.

Obviously in this case we do want to use the debugger, so press F5 (or click the Start button).

[size=-1]Starting the Debugger

The output console will appear normally while the debugger starts (which may take some time -- the breakpoint will appear with a question mark while it starts). Then Visual Studio will be brought back to the foreground, now with a yellow arrow in the margin on top of the red breakpoint dot:

[size=-1]The Debugger is Starting


[size=-1]The Breakpoint is Hit

This yellow arrow indicates which statement will execute next. Commit that to memory, since it's easy to forget when you're looking at a larger piece of code. The statement that is highlighted has not been executed yet, but it will execute next.

[size=+1]Watching Variables
Before we execute that code, we want to make use of the debugger's other primary tool: the ability to look at the contents of variables. The "Autos" window should appear automatically when you start the debugger, but if it doesn't you can access it in the Debug menu. Click Debug > Windows > Autos.

[size=-1]Open the Autos Window

The "Locals" and "Watch" windows are also available from this menu. What the Autos window shows is a list of all the variables you're using in this function:

[size=-1]The Autos Window

Right now all you've got is 'cout' and that doesn't really help. The debugger knows 'a' and 'b' exist, but since you haven't used them it's trying not to clutter the list too much. On the other hand, it sees you're about to use cout and thinks you might want to see its "value."

Once you get to the point of storing values in 'a' and 'b' the Autos list will include them too, but if you don't see the variables you want there are two other options. The "Locals" and "Watch" windows (also accessable from the Debug menu) are similar, they just show different variables.

Locals will show all the variables that are local to this function -- 'a' and 'b' in this case. The Watch windows all let you type in whatever variables or expressions are really interesting to you -- they won't contain anything initially, but you can add entries just by typing an expression. Below I've entered (a + b) as an example.

Note that there are four Watch windows (Watch 1, Watch 2, Watch 3, Watch 4) that all work exactly the same way. You can keep four lists of interesting variables that may be interesting at different times. That can be immensely helpful if you're tracking down several problems at once, or looking for potential problems in several different functions.

[size=-1]The Locals and Watch Windows

Usually the "Autos" window will contain the information you want, so we'll use that for now. Consider that the default, and use the other two if you need extra information.

[size=+1]Stepping
Now we'd like to execute the statement that's highlighted and see what effects it has. The "Step Over" command will do this, and the easiest way to perform a "Step Over" is by pressing the F10 key. Even if you don't normally use keyboard shortcuts, you will probably find it helpful to be able to concentrate on your code while you're using the debugger, so this particular keyboard shortcut is worth knowing. You can also use the Step Over icon:

[size=-1]Step Over

The yellow arrow advances to the next line, which indicates that the statement is done executing, and if you switch to the output window you'll see the result -- the string you asked it to output is displayed. You haven't asked for input yet, so although the console will still let you type it won't really affect your program. Don't type anything yet.

Since that statement didn't accomplish much, Step Over the cin statement next. The console will be brought to the foreground so you can enter data -- enter the same values as before in case the bug depends on those particular values.

Once you've entered the two numbers, the debugger will come back to the foreground with the yellow arrow advanced once again. There's another change though, that's far more important: the variables in the Autos window have changed:


[size=-1]The Variables have Changed

Notice that the values are in red, indicating that they changed when you executed that line. If you're watching many things at once, this helps you figure out which information is new. Since the result of the statement was what we expected, it's unlikely that there's anything wrong. That's the key to this whole process.

Since that statement didn't seem to cause any problems, execute the next by performing another Step Over.

[size=-1]A Second Change

Now 'b' is black again, meaning it did not change when the last statement executed but 'a' is still red. It changed a second time, and clearly the two numbers are equal now. We found the problem! The key is that the change happened after that particular line of code executed, so that's the line that directly caused the problem.

Of course, when you examine it closely you can see that it should have had == instead of = and that certainly explains the incorrect results. Stop the debugger by clicking the stop button, then make the change. Run the program normally to see if your correction actually fixed the bug. Don't remove any breakpoints or Watch variables until you're sure you've solved the problem -- otherwise you'll just have to do it all over again.

[size=+1]Step Into, Step Out
We've already discussed what the "Step Over" button does, but there are two more icons on the debugger toolbar that look quite similar. Their functions are related, so let's discuss them now. When you "Step Over" a statement, the entire statement is executed - including any function calls. What if you want to step into a function and see what happens inside though? That's where you'd use the "Step Into" command.

Step Into

Just like the "Step Over" icon, which shows the arrow leading completely OVER the code, the "Step Into" icon shows an arrow leading INTO the code (relate that logic to what the commands do and it will be easy to remember which icon you want). You can also press F11 to perform a "Step Into."

You should consider "Step Over" the default -- always use that unless you specifically want to examine the innards of a function. Even if you are in the habit of pressing F10, however, you will undoubtedly step into a function by mistake from time to time. The "Step Out" command is the way to remedy that mistake. Performing a "Step Out" tells the debugger to run the current function in its entirety and then stop.

Commit that to memory, since you will undoubtedly need it in time: when you step into a function by mistake, use the "Step Out" command to effectively undo that mistake.

[size=+1]Conditional Breakpoints
Whenever you have a piece of code that runs more than once, it can create a problem for debugging. Suppose, for example, that you have a loop that works for 100 iterations, but then fails for some reason. (This could easily happen if you were processing elements in a large array, for example.) Setting an ordinary breakpoint wouldn't help much, since the breakpoint would be hit every single time through the loop.

Visual Studio lets you set breakpoints conditionally, however, so the program will only stop if a particular condition is met. To give a breakpoint a condition, set the breakpoint normally, then right-click and select "Breakpoint Properties."

Breakpoint Properties

You can make a breakpoint conditional in several ways:
  • You can tell the breakpoint to trigger only after it has been hit n times. This is the "Hit Count" method. Note that this is a count of how many times the breakpoint itself is encountered, so if the breakpoint is inside an 'if' statement, the "Hit Count" may or may not match the number of iterations of the loop.

    You can also tell the program to stop when the hit count is anything above n, or even if it's a multiple of n (so you can check on a loop's progress every 500 iterations, for example.

    Click the "Hit Count" button on the Breakpoint Properties window to change these settings.

    Breakpoint: Hit Count
  • You can tell the breakpoint to stop the program only if some (arbitrary) condition is met. You might do this if there's a particular scenario you're interested in studying (for example, you might want to observe all situations in a loop where some variable is negative).

    From the Breakpoint Properties window, click the "Condition" button and set whatever condition you want:

    Set a Condition
  • If you're interested in stopping whenever some variable (or expression) has changed, you can set a conditional breakpoint in a different way. In the "Breakpoint Condition" window, there are two choices marked "is true" and "has changed." We used the first when we wanted to stop the program only under certain circumstances. The second can be used to monitor a variable.

    If you entered 'someVar' in the "Condition" field, and checked "hasChanged," then the breakpoint would only stop on iterations where the value of 'someVar' is different from when it was last seen. Although conditional breakpoints are most often useful inside loops, there's no reason they must be used inside a loop. This is just one more tool you have available; it may be handy in any number of situations.
[size=+1]Summary
Ultimately the debugger just gives you the ability to follow the execution of your code closely, and the ability to watch the contents of variables. Although this example was extremely simplified, exactly the same technique applies to programs of any size.

The Technique:
  • Identify a general part of the program that may be at fault.
  • Set a breakpoint at the beginning of that area.
  • Step through your code one line at a time, and watch any interesting variables for changes.
  • Whenever something unexpected happens, scrutinize that line very closely - there's something wrong!

[size=+1]Practice
The only way you'll really learn the debugger is to use it. Introduce errors in your own programs deliberately so you can observe the debugger's behavior for problems you already understand. Then use the debugger whenever you encounter an error (even a simple error you could probably solve on your own) for the sake of practicing.
您需要登录后才可以回帖 登录 | 申请新用户

本版积分规则

守望轩 ( 湘ICP备17013730号-2 )|网站地图

GMT+8, 2024-4-24 07:50 , Processed in 0.051955 second(s), 16 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表