Main Page

Previous Page
Next Page

[Page 1382 (continued)]

M.2. Breakpoints and the run, stop, continue and print Commands

We begin our study of the debugger by investigating breakpoints, which are markers that can be set at any executable line of code. When program execution reaches a breakpoint, execution pauses, allowing you to examine the values of variables to help determine whether logic errors exist. For example, you can examine the value of a variable that stores the result of a calculation to determine whether the calculation was performed correctly. Note that attempting to set a breakpoint at a line of code that is not executable (such as a comment) will actually set the breakpoint at the next executable line of code in that function.

To illustrate the features of the debugger, we use the program listed in Fig. M.3, which creates and manipulates an object of class Account (Figs. M.1M.2). Execution begins in main (lines 1230 of Fig. M.3). Line 14 creates an Account object with an initial balance of $50.00. Account's constructor (lines 1022 of Fig. M.2) accepts one argument, which specifies the Account's initial balance. Line 17 of Fig. M.3 outputs the initial account balance using Account member function getBalance. Line 19 declares a local variable withdrawalAmount which stores a withdrawal amount read from the user. Line 21 prompts the user for the withdrawal amount; line 22 inputs the amount into withdrawalAmount. Line 25 subtracts the withdrawal from the Account's balance using its debit member function. Finally, line 28 displays the new balance.

[Page 1383]

Figure M.1. Header file for the Account class.

 1  // Fig. M.1: Account.h
 2  // Definition of Account class.
 4  class Account
 5  {
 6  public:
 7     Account( int ); // constructor initializes balance
 8     void credit( int ); // add an amount to the account balance
 9     void debit( int ); // subtract an amount from the account balance
10     int getBalance(); // return the account balance
11  private:
12     int balance; // data member that stores the balance
13  }; // end class Account

Figure M.2. Definition for the Account class.
(This item is displayed on pages 1383 - 1384 in the print version)

 1  // Fig. M.2: Account.cpp
 2  // Member-function definitions for class Account.
 3  #include <iostream>
 4  using std::cout;
 5  using std::endl;
 7  #include "Account.h" // include definition of class Account
 9  // Account constructor initializes data member balance
10  Account::Account( int initialBalance )
11  {
12     balance = 0; // assume that the balance begins at 0
14     // if initialBalance is greater than 0, set this value as the
15     // balance of the Account; otherwise, balance remains 0
16     if ( initialBalance > 0 )
17        balance = initialBalance;
19     // if initialBalance is negative, print error message
20     if ( initialBalance < 0 )
21        cout << "Error: Initial balance cannot be negative.\n" << endl;
22  } // end Account constructor
24  // credit (add) an amount to the account balance
25  void Account::credit( int amount )
26  {
27     balance = balance + amount; // add amount to balance
28  } // end function credit
30  // debit (subtract) an amount from the account balance
31  void Account::debit( int amount )
32  {
33     if ( amount <= balance ) // debit amount does not exceed balance
34        balance = balance - amount;
36     else // debit amount exceeds balance
37        cout << "Debit amount exceeded account balance.\n" << endl;
38  } // end function debit
40  // return the account balance
41  int Account::getBalance()
42  {
43     return balance; // gives the value of balance to the calling function
44  } // end function getBalance

[Page 1384]

Figure M.3. Test class for debugging.

 1  // Fig. M.3: figM_03.cpp
 2  // Create and manipulate Account objects.
 3  #include <iostream>
 4  using std::cin;
 5  using std::cout;
 6  using std::endl;
 8  // include definition of class Account from Account.h
 9  #include "Account.h"
11  // function main begins program execution
12  int main()
13  {
14     Account account1( 50 ); // create Account object
16     // display initial balance of each object
17     cout << "account1 balance: $" << account1.getBalance() << endl;
19     int withdrawalAmount; // stores withdrawal amount read from user
21     cout << "\nEnter withdrawal amount for account1: "; // prompt
22     cin >> withdrawalAmount; // obtain user input
23     cout << "\nattempting to subtract " << withdrawalAmount
24        << " from account1 balance\n\n";
25     account1.debit( withdrawalAmount ); // try to subtract from account1
27     // display balances
28     cout << "account1 balance: $" << account1.getBalance() << endl;
29     return 0; // indicate successful termination
30  } // end main

In the following steps, you will use breakpoints and various debugger commands to examine the value of the variable withdrawalAmount declared in line 19 of Fig. M.3.

Compiling the program for debugging. The GNU debugger works only with executable files that were compiled with the -g compiler option, which generates information that is used by the debugger to help you debug your programs. Compile the program with the -g command-line option by typing g++ -g -o figM_03 figM_03.cpp Account.cpp.

[Page 1385]
Starting the debugger. Type gdb figM_03 (Fig. M.4). This command will start the GNU debugger and display the (gdb) prompt at which you can enter commands.

Figure M.4. Starting the debugger to run the program.

 ~/Debug$ gdb figM_03
 GNU gdb 6.1-debian
 Copyright 2004 Free Software Foundation, Inc.
 GDB is free software, covered by the GNU General Public License, and you are
 welcome to change it and/or distribute copies of it under certain conditions.
 Type "show copying" to see the conditions.
 There is absolutely no warranty for GDB. Type "show warranty" for details.
 This GDB was configured as "i386-linux"...Using host libthread_db library "/


Running a program in the debugger. Run the program through the debugger by typing run (Fig. M.5). If you do not set any breakpoints before running your program in the debugger, the program will run to completion.

Figure M.5. Running the program with no breakpoints set.

 (gdb) run
 Starting program: /home/student/Debug/figM_03
 account1 balance: $50

 Enter withdrawal amount for account1: 13

 attempting to subtract 13 from account1 balance

 account1 balance: $37

 Program exited normally.

Inserting breakpoints using the GNU debugger. You set a breakpoint at a specific line of code in your program. The line numbers used in these steps are from the source code in Fig. M.3. Set a breakpoint at line 17 in the source code by typing break 17. The break command inserts a breakpoint at the line number specified after the command. You can set as many breakpoints as necessary. Each breakpoint is identified in terms of the order in which it was created. The first breakpoint created is known as Breakpoint 1. Set another breakpoint at line 25 by typing break 25 (Fig. M.6). When the program runs, it suspends execution at any line that contains a breakpoint and the program is said to be in break mode. Breakpoints can be set even after the debugging process has begun. [Note: If you do not have a numbered listing for your code, you can use the list command to output your code with line numbers. For more information about the list command type help list from the gdb prompt.]

[Page 1386]

Figure M.6. Setting two breakpoints in the program.

 (gdb) break 17
 Breakpoint 1 at 0x80487d8: file figM_03.cpp, line 17.
 (gdb) break 25
 Breakpoint 2 at 0x8048871: file figM_03.cpp, line 25.

Running the program and beginning the debugging process. Type run to execute your program and begin the debugging process (Fig. M.7). The program pauses when execution reaches the breakpoint at line 17. At this point, the debugger notifies you that a breakpoint has been reached and displays the source code at that line (17). That line of code contains the next statement that will execute.

Figure M.7. Running the program until it reaches the first breakpoint.

 (gdb) run
 Starting program: /home/student/Debug/figM_03

 Breakpoint 1, main () at figM_03.cpp:17
 17         cout << "account1 balance: $" << account1.getBalance() << endl;

Using the continue command to resume execution. Type continue. The continue command causes the program to continue running until the next breakpoint is reached (line 25). Enter 13 at the prompt. The debugger notifies you when execution reaches the second breakpoint (Fig. M.8). Note that figM_03's normal output appears between messages from the debugger.

Figure M.8. Continuing execution until the second breakpoint is reached.

 (gdb) continue
 account1 balance: $50

 Enter withdrawal amount for account1: 13

 attempting to subtract 13 from account1 balance

 Breakpoint 2, main () at figM_03.cpp:25
 25         account1.debit( withdrawalAmount ); // try to subtract from

[Page 1387]
Examining a variable's value. Type print withdrawalAmount to display the current value stored in the withdrawalAmount variable (Fig. M.9). The print command allows you to peek inside the computer at the value of one of your variables. This command will help you find and eliminate logic errors in your code. Note that the value displayed is 13the value read in and assigned to withdrawalAmount in line 22 of Fig. M.3. Use the print command to output the contents of the account1 object. When an object is output through the debugger with the print command, the object is output with braces surrounding the object's data members. In this case, there is a single data memberbalancewhich has a value of 50.

Figure M.9. Printing the values of variables.

 (gdb) print withdrawalAmount
 $1 = 13
 (gdb) print account1
 $2 = {balance = 50}

Using convenience variables. When the print command is used, the result is stored in a convenience variable such as $1. Convenience variables, which are temporary variables, named using a dollar sign followed by an integer, are created by the debugger as you print values during your debugging session. A convenience variable can be used in the debugging process to perform arithmetic and evaluate boolean expressions. Type print $1. The debugger displays the value of $1 (Fig. M.10), which contains the value of withdrawalAmount. Note that printing the value of $1 creates a new convenience variable$3.

Figure M.10. Printing a convenience variable.

 (gdb) print $1
 $3 = 13

Continuing program execution. Type continue to continue the program's execution. The debugger encounters no additional breakpoints, so it continues executing and eventually terminates (Fig. M.11).

Figure M.11. Finishing execution of the program.

 (gdb) continue
 account1 balance: $37

 Program exited normally.

[Page 1388]
Removing a breakpoint. You can display a list of all of the breakpoints in the program by typing info break. To remove a breakpoint, type delete, followed by a space and the number of the breakpoint to remove. Remove the first breakpoint by typing delete 1. Remove the second breakpoint as well. Now type info break to list the remaining breakpoints in the program. The debugger should indicate that no breakpoints are set (Fig. M.12).

Figure M.12. Viewing and removing breakpoints.

 (gdb) info break
 Num Type           Disp Enb Address    What
 1   breakpoint     keep y   0x080487d8 in main at figM_03.cpp:17
         breakpoint already hit 1 time
 2   breakpoint     keep y   0x08048871 in main at figM_03.cpp:25
         breakpoint already hit 1 time
 (gdb) delete 1
 (gdb) delete 2
 (gdb) info break
 No breakpoints or watchpoints.

Executing the program without breakpoints. Type run to execute the program. Enter the value 13 at the prompt. Because you successfully removed the two breakpoints, the program's output is displayed without the debugger entering break mode (Fig. M.13).

Figure M.13. Program executing with no breakpoints set.

 (gdb) run
 Starting program: /home/student/Debug/figM_03
 account1 balance: $50

 Enter withdrawal amount for account1: 13

 attempting to subtract 13 from account1 balance

 account1 balance: $37

 Program exited normally.

Using the quit command. Use the quit command to end the debugging session (Fig. M.14). This command causes the debugger to terminate.

Figure M.14. Exiting the debugger using the quit command.

 (gdb) quit

[Page 1389]

In this section, you learned how to enable the debugger using the gdb command and run a program with the run command. You saw how to set a breakpoint at a particular line number in the main function. The break command can also be used to set a breakpoint at a line number in another file or at a particular function. Typing break, then the filename, a colon and the line number will set a breakpoint at a line in another file. Typing break, then a function name will cause the debugger to enter the break mode whenever that function is called.

Also in this section, you saw how the help list command will provide more information on the list command. If you have any questions about the debugger or any of his commands, type help or help followed by the command name for more information.

Finally, you learned to examine variables with the print command and remove breakpoints with the delete command. You learned how to use the continue command to continue execution after a breakpoint is reached and the quit command to end the debugger.

Previous Page
Next Page