310 likes | 515 Views
C++ Debugging (in Visual Studio and emacs). We’ve looked at programs from a text-based mode Shell commands and command lines Text editors, compiler, linker How the program receives input and generates output General program structure and logic We’ve also looked at Visual Studio
E N D
C++ Debugging (in Visual Studio and emacs) • We’ve looked at programs from a text-based mode • Shell commands and command lines • Text editors, compiler, linker • How the program receives input and generates output • General program structure and logic • We’ve also looked at Visual Studio • In which all of these functions are integrated… • …within a nice graphical environment • Today we’ll bring those perspectives together • Debug a simple example program in Visual Studio • Look at how do the same thing within emacs
Getting Started • To set up your own environment for what we’ll cover • Log on and then ssh into grid.cec.wustl.edu • Create a new directory (e.g., mkdir prefix_adder) • Save files from course web page (or copy them from the ~cse232/.www-docs/ directory) into that directory: Makefile prefix_adder.h prefix_adder.cc • Also download those files to your Windows desktop • Create a new project in Visual Studio • Copy those files into the new project in Visual Studio • Build the project
Debugging an Example Program • Now we’ll use Visual Studio to debug a program • Step through (and into) functions • Watching the call stack and variable values • But, before we start using Visual Studio… • What are we trying to achieve? • What do we expect our program to do? • How might our program fail? • Can we make predictions and test them? • Thinking: the most powerful way to debug • Scientific method should guide what you do • hypothesis, prediction, experiment, analysis • Tools can help you follow this disciplined approach faster
What the Example Program Does • Called with command line arguments ./prefix_adder + 8 + 9 10 • Calculates prefix addition expressions + 8 + 9 10 + + 8 9 10 • These are equivalent to their infix versions (8 + (9 + 10)) ((8 + 9) + 10) • Key idea: walk through expresion, calculate value same result different order 1 1 + + 2 3 2 5 8 + + 10 4 5 3 4 9 8 10 9
How the Example Program Can Fail • Too few arguments in expression ./prefix_adder + 8 + 9 • Cannot calculate result + 8 + 9 (needs another value to finish 2nd + operation) • Exercise: try this on your own, for practice 1 + 2 3 8 + 4 ??? 9
Example Program: Header File // prefix_adder.h // // author: Chris Gill cdgill@cse.wustl.edu // // purpose: Declarations for a simple prefix adder program, which // takes the command line arguments as a prefix addition // expression and computes an integer result. #ifndef PREFIX_ADDER_H #define PREFIX_ADDER_H // Function prototypes. void usage (char * program_name); int parse_and_compute (int & current_index, int last_index, char *argv[]); #endif /* PREFIX_ADDER_H */
Example Program: Start of the Source File // prefix_adder.cc // // author: Chris Gill cdgill@cse.wustl.edu // // purpose: definitions for a simple prefix adder program, which // takes the command line arguments as a prefix addition // expression and computes an integer result. #include "prefix_adder.h" #include <iostream> // For std output stream and manipulators. #include <string> // For standard C++ strings. #include <sstream> // For standard string streams. #include <cstring> // For C-style string functions // Helper function to print out the program's usage message. void usage (char * program_name) { cout << "Usage: " << program_name << " <argument> [<argument>]..." << endl << "Purpose: computes program arguments as prefix addition expression" << endl; }
Example Program: Main Function int main (int argc, char *argv[]) { // A few useful constants for argument positions const int minimum_arguments = 2; const int starting_index = 1; const int program_name_index = 0; if (argc < minimum_arguments || strcmp (argv[starting_index], "--help") == 0) { usage (argv[program_name_index]); return 1; } try { // Pass the current and last index to use, and the array, to the // expression parsing function, and store the result. int current_position = starting_index; int value = parse_and_compute (current_position, argc - 1, argv); // Print out the result, and return success value. cout << "The value calculated is " << value << endl; return 0; } catch (...) { cout << "caught exception" << endl; return -1; } }
Example Program: Parsing Function // Helper function to parse the input symbols and compute a value. int parse_and_compute (int & current_index, int last_index, char *argv[]) { // make sure we're still in the argument range if (current_index > last_index) { throw; } // look for a single-symbol addition operator if (strlen (argv[current_index]) == 1 && *(argv[current_index]) == '+') { int first_operand = parse_and_compute (++current_index, last_index, argv); int second_operand = parse_and_compute (current_index, last_index, argv); return first_operand + second_operand; } // treat anything else as an integer else { int result; istringstream i (argv[current_index++]); i >> result; return result; } } • Exercise: • Set a break point at the first if statement in this function • Watch how stack grows/shrinks if you have debug continue
Exercise • Build and debug a damaged version of the program • Save another file from course web page into the project (or create a new project with same Makefile and header file) bad_prefix_adder.cc • Build the new version of the program • Debug what’s wrong with the program (no fair using diff to detect code differences ;-) • Run the program with different inputs • Observe what happens (how does it go wrong?) • Trace through the program in Visual Studio to narrow down the possible cause(s) of the problem(s) • If you’d like to, also try the same thing in emacs • Fix the error(s), rebuild, and re-run to observe its behavior