Standard I/O and Iostream, Getopt(), Make, Gdb, Unit Testing
Total Page:16
File Type:pdf, Size:1020Kb
Data Structures Contents and Algorithms ! C++ Input/Output ! getopt ! Makefile ! gdb Discussion 1: Week of Sep 7, 2011 ! Unit Testing 2 C++ Input/Output C++ Input/Output ! !"#$%&'()%*&+,%-.)"#% ! !+/.$%0&".'%.+%-.)+/.% ! !'&&$%0&".'%.+%-.)'&&% ! "*-.&'(,$%+1'#%*"2'-%0".3%&'()%1'&,"--"+#% ! *-.&'(,$%+1'#%*"2'-%0".3%&'()%4%0&".'% 1'&,"--"+#% http://www.cplusplus.com/reference/ 3 4 PA1 Read char by char ! 5#1/.6+/.1/.%"-%&')"&'!.')%*&+,%*"2'-% "#.%,("#C"#.%(&@!A%!3(&DD%(&@EF% ! 761(.389:%;%"#1/.7.<.%=%+/.1/.7.<.% G% ! >;>%(#)%>"#1/.7.<.?%(&'%#+.%!+,,(#)%2"#'%(&@-A% %03"2'C!"#7@'.CF%HI%J:F% )+%#+.%(11'(&%"#%char** argv %G% ! B+/%!(#%/-'%% %%!"#7/#@'.CFK% cin.get(), cin.unget(), getline(cin, var), %%!3(&%!%I%!"#7@'.CFK% cin >> var %%!+/.%;;%!K% %L% %&'./&#%MK% L% 5 6 Command Line Read line by line ! Option: defines how the program should run "#.%,("#C"#.%(&@!A%!3(&DD%(&@EF% ! Argument: input to the program G% ! $ ls –a (-a is an option) %-.&"#@%-K% ! $ ls *.cpp (*.cpp is an argument) %03"2'C@'.2"#'C!"#A-FF% ! $ mysql –p –u username (username is required by option –u) %G% %%!+/.%;;%-%;;%'#)2K% %L% %&'./&#%MK% L% 7 8 getopt getopt – external variable soup ! getopt greatly simplifies command-line argument parsing. ! getopt gets and sets some external variables on execution: ! We pass it argc and argv, as well as optstring, which is a – If you set opterr to something other than zero, then if character array containing all available option characters. there is an error, it will be output to stderr. – After an option character, you can specify a : to indicate – For unknown option characters/unknown arguments, that the option has a required parameter. :: denotes that getopt stores the value in optopt. the argument is optional. – optind contains the index of the next element of argv ! getopt returns the option if it successfully found one. scheduled to be processed. – ! Otherwise, it might return : which indicates a missing For options that accept arguments, optarg is set with the parameter value of the argument. • ! Or it might return ? which means one of the option characters Windows users can get wingetopt from: was unknown http://note.sonots.com/Comp/CompLang/cpp/getopt.html ! Let's look at an example. ! Or it will return -1 if it is at the end of the option list 9 10 getopt getopt #include <unistd.h> % testopt #include <stdio.h> aflag = 0, bflag = 0, cvalue = (null) int main (int argc, char **argv) { % testopt -a -b int aflag = 0; int bflag = 0; aflag = 1, bflag = 1, cvalue = (null) char *cvalue = NULL; int index, c; % testopt -ab opterr = 0; // extern var aflag = 1, bflag = 1, cvalue = (null) while ((c = getopt (argc, argv, "abc:")) != -1) { % testopt -c foo switch (c) { aflag = 0, bflag = 0, cvalue = foo case 'a': aflag = 1; break; % testopt -cfoo case 'b': aflag = 0, bflag = 0, cvalue = foo bflag = 1; break; case 'c': % testopt arg1 cvalue = optarg; break; aflag = 0, bflag = 0, cvalue = (null) case '?': Non-option argument arg1 if (isprint (optopt)) fprintf (stderr, "Unknown option `-%c'.\n", optopt); % testopt -a arg1 else aflag = 1, bflag = 0, cvalue = (null) fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt); Non-option argument arg1 return 1; default: % testopt -c foo arg1 abort (); aflag = 0, bflag = 0, cvalue = foo } Non-option argument arg1 printf ("aflag = %d, bflag = %d, cvalue = %s\n", % testopt -a -- -b aflag, bflag, cvalue); aflag = 1, bflag = 0, cvalue = (null) Non-option argument -b for (index = optind; index < argc; index++) printf ("Non-option argument %s\n", argv[index]); % testopt -a - return 0; aflag = 1, bflag = 0, cvalue = (null) } 11 Non-option argument - Compiling: The old way The Solution: Makefiles ! @NN%,("#7!11%*"2':7!11%*"2'87!11%O+%,("#% ! The command becomes " Way too long to re-type over and over. " ,(P'% " Compare to ! Potential Problems: " @NN%,("#7!11%*"2':7!11%*"2'87!11%O+%,("#% " @NN%,("#%O+%,("#7!11% " @NN%,("#7!11%O+%,("#7!11% ! What happens in the two above commands? 13 14 Structure of a Makefile Dependencies ! The file must be called `Q(P'*"2'’ ! It consists of rules as follows: 15 16 make make ! Let's look at an example 3-file project. ! make is a utility that can simplify the building process. classname.h As the size of a C++ project grows, it becomes critical to void writeClassName( void ); modularize the code for the sake of both the build time classname.cpp and for the sanity of the programmer (and the grader!). #include <iostream> ! make is better than a shell script because it detects the using namespace std; files that have been changed and only recomplies and void writeClassName( void ) { relinks when needed. cout << "Hello EECS 281!" << endl; } ! make looks at a file called Makefile, created by you, to hello.cpp determine the dependency graph of your project. #include <iostream> #include "classname.h" using namespace std; int main( void ) { cout << "Hello world!" << endl; writeClassName(); } 17 18 make - Makefile make – macros ! Here is our simple Makefile: ! It's possible to define and use macros in your Makefile: # top-level dependency OBJECTS = hello.o classname.o helloWorld281: hello.o classname.o CPPFLAGS = -c -Wall g++ hello.o classname.o -o helloWorld281 # top-level dependency # hello module helloWorld281: $(OBJECTS) hello.o: hello.cpp classname.h g++ $(OBJECTS) -o helloWorld281 g++ -c hello.cpp # hello module # the classname module hello.o: hello.cpp classname.h classname.o: classname.cpp classname.h g++ $(CPPFLAGS) hello.cpp g++ -c classname.cpp # the classname module ! We define a dependency graph in Makefile. To the left of the colon classname.o: classname.cpp classname.h g++ $(CPPFLAGS) classname.cpp is a label often denoting a file. To the right are dependencies. For example, helloWorld281 depends on hello.o and classname.o. # clean the project clean: ! The indented lines are, in a nutshell, the commands executed to rm -rf *o helloWorld281 create the object denoted by the label. Compiled in order. These ! Note above we've also defined a “clean” operation. This is an lines must be indented. action, not a g++ operation. To use, type make clean at the command prompt. ! # denotes comments 19 20 make - sub-makefiles make ! You can also embed other makefiles inside Makefile. This allows ! make is a powerful and complex utility, and we're just barely you to modularize your build process even further. To specify a scratching the surface. For more information, do a man make or make file with a different name than Makefile, use the -f option: check out one of the many tutorials on the web. make -f MyOtherMakeFile ! http://www.eng.hawaii.edu/Tutor/Make/ 21 22 Makefiles Summary Makefiles Summary ! Basic syntax " Target: sources ! Suppose we run the following command to compile our " [tab] system command program: " g++ main.cpp hello.cpp factorial.cpp -o hello ! To run a makefile, simply use: ! Then we can do the same thing in our makefile by just " make -f makefilename doing this: ! BUT, if you simply name your makefile all: “Makefile”, then you only have to type: g++ main.cpp hello.cpp factorial.cpp -o hello ! Remember tabs, of course make ! All is default target for makefiles. That's why it works here. Makefiles Summary GNU Debugger (gdb) ! Dependencies are important! ! Here is an example makefile for the same source code: ! Text-based debugging tool all: hello hello: main.o factorial.o hello.o ! Useful for solving segmentation faults g++ main.o factorial.o hello.o -o hello main.o: main.cpp Program received signal SIGSEGV, Segmentation fault. g++ -c main.cpp factorial.o: factorial.cpp or memory issues, e.g., index out of bounds g++ -c factorial.cpp hello.o: hello.cpp g++ -c hello.cpp clean: rm -rf *o hello ! When compiling, add -g to Makefile ! What advantages does this code have? " Adds debugging symbols to binary 26 gdb Helpful Commands gdb Usage # (r)un: start the executable # (b)reak: sets points where gdb will halt # where: prints function line where seg. fault occurred ! To start gdb, type gdb <exe name> # (b)ack(t)race: prints the full chain of function calls # (s)tep: executes current line of the program, enters function calls # (n)ext: like step but does not enter functions # (c)ontinue: continue to the next breakpoint # (p)rint <var>: prints the value of <var> # watch <var>: watch a certain variable # (l)ist <line_num> : list source code near <line_num> ! At this point, gdb is waiting. To start the # kill: terminate the executable program, type run <command line> # (q)uit: quit gdb 27 28 Unit Testing gdb Live Example ! Unit testing is a methodology by which you test the software of your program. ! Tests are unit tests because they usually operate on a ! See live example" small, specific part of the system. ! They are organized in classes. ! We can implement an extremely simple version of unit testing with assert. 29 37 Unit testing Unit Testing PowerRaiser.h ! assert is the most important macro in C++ (at least in terms of debugging). class PowerRaiser { public: ! We assert that something is true. If, when the PowerRaiser( unsigned int base ); program counter reaches an assert and the expression unsigned int getBase() const; turns out to be false, it triggers a breakpoint, and we unsigned int raise( unsigned int power ) const; break into the code. private: unsigned int base_; ! It's incredibly useful and convenient. Use it! }; assert( 3 == 3 ); // OK assert( false == false ); // OK assert( myFunc( 123 ) ); // OK if myFunc returns true assert( 5 == 2 + 2 ); // Will break into code!!!! 39 Unit Testing Unit Testing PowerRaiser.cpp PowerRaiserTest.h PowerRaiser::PowerRaiser( unsigned int base ) : class PowerRaiserTest { base_( base ) public: { void runAllTests(); } void testGetBase(); void testGetPower(); unsigned int PowerRaiser::getBase() const { ... return base_; }; } unsigned int PowerRaiser::raise( unsigned int power ) const { if ( 0 == number ) { return 1; } else { return base_ * raise( power – 1 ); } 40 41 Unit Testing Unit Testing PowerRaiserTest.cpp ! Each time we make a change to the code base, we void PowerRaiserTest::testGetBase() { run all unit tests to make sure that all of the PowerRaiser p( 10 ); functionality is still there.