140 likes | 230 Views
ECE230 Lectures Series. Debugging: Catching Bugs ( I ). Ying Wu Electrical & Computer Engineering Northwestern University yingwu@ece.northwestern.edu. A Little Challenged?. Keys in programming Your solution design Language syntax code Debugging skills working programs
E N D
ECE230 Lectures Series Debugging: Catching Bugs ( I ) Ying Wu Electrical & Computer Engineering Northwestern University yingwu@ece.northwestern.edu
A Little Challenged? • Keys in programming • Your solution design • Language syntax code • Debugging skills working programs • Never stop improving good programs • The role of the compiler • Very very little: acting like a grammar checker • Your role in programming • You need to have a solution • You need to make sure what you code is what you want • You need to make sure there is no bugs in your code • Overwhelmed? • Don’t panic! Life is not as bad as you may think.
Outline • Introduction • What is debugging • Why do we need debugging • What do you need to have • A simple way • testing a black box • printing out intermediate results • Assert yourself • assert( ) • Stepping through your code (see next lecture) • Debugging tools
What is a bug? • Syntax errors are easy to fix • Once you’ve understood all the syntax • But a run-time failure is most likely caused by • Logic bugs • Overflow and underflow bugs • Data conversion bugs • Wild pointer bugs • Garbage memory bugs • …
input output your code Debugging What is debugging? • Always make sure you know what you are expecting from the code • If your program did not output what you expected, tract it down to the exact point • You will find the bug! • Go ahead and fix it.
Why? • The complier will never catch bugs • The complier only check syntax errors • It will never check if your code would fulfill your tasks. • You are on you own to • make your program correct • make your program robust • make sure what is really going on in your code • There is no magic in programming
What do you need? • Deep understanding of the language itself • Fundamentals on low-level programming • Debugging tools • Good coding style • Right attitude
print_array(b); cout << key << low << high << size << endl; // Binary search int binarySearch( const int b[], int searchKey, int low, int high, int size ) { int middle; while ( low <= high ) { middle = ( low + high ) / 2; if ( searchKey == b[ middle ] ) // match return middle; else if ( searchKey < b[ middle ] ) high = middle - 1; // search low end of array else low = middle + 1; // search high end of array } return -1; // searchKey not found } cout << low << middle << high << endl; print_array(b, low, high); cout << low << middle << high << endl; print_array(b, low, high);
A Tale of Two Versions • Release version • Clean • Fast • Debug version • Contains many debug information • Big and slow • Using macro #ifdef, for example #ifdef DEBUG // print_out_stuff … #endif • Maintain both versions for your program
#define DEBUG // Binary search int binarySearch( const int b[], int searchKey, int low, int high, int size ) { int middle; while ( low <= high ) { middle = ( low + high ) / 2; if ( searchKey == b[ middle ] ) // match return middle; else if ( searchKey < b[ middle ] ) high = middle - 1; // search low end of array else low = middle + 1; // search high end of array } return -1; // searchKey not found } #ifdef DEBUG print_array(b); cout << key << low << high << size << endl; #endif #ifdef DEBUG cout << low << middle << high << endl; print_array( b, low, high ); #endif
Introducing assert • assert is a macro defined in <cassert> • Functionality • Test the value of an expression • If the value of the exp is 0, then assert • prints an error message • call function abort() (which is defined in <cstdlib>) • If not, do nothing • To cancel all assertion, use #define NDEBUG • Some symbolic constant • Line number of current code __LINE__ • Name of current source file __FILE__
Assert Yourself • Do not wait for bugs to happen • Use startup checks • Use assertions • To validate function arguments • To detect impossible conditions • To catch illegal uses of undefined behavior
#include <cassert> #include <cstdlib> // Binary search int binarySearch( const int b[], int searchKey, int low, int high, int size ) { int middle; while ( low <= high ) { middle = ( low + high ) / 2; if ( searchKey == b[ middle ] ) // match return middle; else if ( searchKey < b[ middle ] ) high = middle - 1; // search low end of array else low = middle + 1; // search high end of array } return -1; // searchKey not found } assert ( b != NULL && size > 0 ); assert ( low >= 0 && high <= size-1 ); assert ( low <= high );
pFrom pTo pFrom pTo size = 10 ? pbFrom pbFrom pbTo pbTo typedef unsigned char byte; // memcpy – copy a nonoverlapping memory block void *memcopy(void *pTo, void *pFrom, size_t size) { byte *pbTo = (byte *)pTo; byte *pbFrom = (byte *)pFrom; while ( size-- > 0) *pbTo++ = *pbFrom++; return (pTo); } assert ( pTo != NULL && pFrom != NULL); assert ( pbTo >= pbFrom + size || pbFrom >= pbTo + size );