460 likes | 643 Views
Chapter 20 - C Legacy Code Topics. Outline 20.1 Introduction 20.2 Redirecting Input/Output on UNIX and DOS Systems 20.3 Variable-Length Argument Lists 20.4 Using Command-Line Arguments 20.5 Notes on Compiling Multiple-Source-File Programs
E N D
Chapter 20 - C Legacy Code Topics Outline 20.1 Introduction 20.2 Redirecting Input/Output on UNIX and DOS Systems 20.3 Variable-Length Argument Lists 20.4 Using Command-Line Arguments 20.5 Notes on Compiling Multiple-Source-File Programs 20.6 Program Termination with exit and atexit 20.7 The volatile Type Qualifier 20.8 Suffixes for Integer and Floating-Point Constants 20.9 Signal Handling 20.10 Dynamic Memory Allocation with calloc and realloc 20.11 The Unconditional Branch: goto 20.12 Unions 20.13 Linkage Specifications
20.1 Introduction • Several advanced topics in chapter • Many capabilities specific to OS • Especially UNIX and/or DOS • Chapter for C++ programmers working with C legacy code
20.2 Redirecting Input/Output on UNIX and DOS Systems • Standard I/O • Keyboard (input) and screen (output) • Can redirect I/O • Inputs can come from a file, output can go to a file • Redirect symbol (<) • Operating system feature (not C++ feature!) • UNIX and DOS • $ myProgram < input • myProgram is an executable file • input is a data file • $ is the command-line prompt • Input to program now comes from file input, not the keyboard
20.2 Redirecting Input/Output on UNIX and DOS Systems • Pipe command ( | ) • Output of one program becomes input of another • $ firstProgram | secondProgram • Output of firstProgram goes to secondProgram • Redirect output ( > ) • Output of program goes to a file • $ myProgram > myFile • Output goes tomyFile(erases previous contents)
20.2 Redirecting Input/Output on UNIX and DOS Systems • Append output (>>) • Output of program appends to end of file • $ myProgram >> myFile • Output goes to end of myFile
20.3 Variable-Length Argument Lists • In C++, we use function overloading • Variable-length arguments for programmers working with C • Create functions with unspecified number of arguments • Function format • Include <cstdarg> • Use ellipsis (…) at end of parameter list • Must be last item in parameter list • Must be one named parameter before ellipsis • double myFunction(int i, …);
20.3 Variable-Length Argument Lists • Usage (inside function) • Declare object of type va_list • Holds data needed by other macros • va_list myList; • Run macro va_start • First argument is va_list object • Second is last parameter before ellipsis starts • va_start( myList, i );
20.3 Variable-Length Argument Lists • Usage • Access arguments with macro va_arg • First argument is va_list • Second is the expected type of variable • Returns the value • myArg = va_arg( myList, double ); • Can use different data types for different arguments • Run macro va_end • va_end( myList );
1 // Fig. 20.2: fig20_02.cpp 2 // Using variable-length argument lists. 3 #include <iostream> 4 5 using std::cout; 6 using std::endl; 7 using std::ios; 8 9 #include <iomanip> 10 11 using std::setw; 12 using std::setprecision; 13 using std::setiosflags; 14 using std::fixed; 15 16 #include <cstdarg> 17 18 double average( int, ... ); 19 20 int main() 21 { 22 double double1 = 37.5; 23 double double2 = 22.5; 24 double double3 = 1.7; 25 double double4 = 10.2; 26 Note use of ellipsis in the prototype, and one defined argument before it. fig20_02.cpp(1 of 3)
27 cout << fixed << setprecision( 1 ) << "double1 = " 28 << double1 << "\ndouble2 = " << double2 << "\ndouble3 = " 29 << double3 << "\ndouble4 = " << double4 << endl 30 << setprecision( 3 ) 31 << "\nThe average of double1 and double2 is " 32 << average( 2, double1, double2 ) 33 << "\nThe average of double1, double2, and double3 is " 34 << average( 3, double1, double2, double3 ) 35 << "\nThe average of double1, double2, double3" 36 << " and double4 is " 37 << average( 4, double1, double2, double3, double4 ) 38 << endl; 39 40 return0; 41 42 } // end main 43 Call function with a variable number of arguments (passing the number of arguments as a parameter). fig20_02.cpp(2 of 3)
44 // calculate average 45 double average( int count, ... ) 46 { 47 double total = 0; 48 va_list list; // for storing information needed by va_start 49 50 va_start( list, count ); 51 52 // process variable length argument list 53 for ( int i = 1; i <= count; i++ ) 54 total += va_arg( list, double ); 55 56 // end the va_start 57 va_end( list ); 58 59 return total / count; 60 61 } // end function average Create a va_list object and call macro va_start. count is the parameter before the ellipsis. Extract each argument from list, treat as a double. End the macros, helps with a normal function return. fig20_02.cpp(3 of 3)
double1 = 37.5 double2 = 22.5 double3 = 1.7 double4 = 10.2 The average of double1 and double2 is 30.000 The average of double1, double2, and double3 is 20.567 The average of double1, double2, double3 and double4 is 17.975 fig20_02.cppoutput (1 of 1)
20.4 Using Command-Line Arguments • Can pass arguments to main in UNIX/DOS • Include parameters in main • int main( int argc, char *argv[] ) • int argc • Number of arguments • char *argv[] • Array of strings that contains command-line arguments • Example: $ copy input output argc: 3 argv[0]: "copy" argv[1]: "input" argv[2]: "output"
20.4 Using Command-Line Arguments • Upcoming example • Program to copy input file to output file • copy input output • Read a character from file input and write to file output • Stop when no more characters to read (EOF)
1 // Fig. 20.3: fig20_03.cpp 2 // Using command-line arguments 3 #include <iostream> 4 5 using std::cout; 6 using std::endl; 7 using std::ios; 8 9 #include <fstream> 10 11 using std::ifstream; 12 using std::ofstream; 13 14 int main( int argc, char *argv[] ) 15 { 16 // check number of command-line arguments 17 if ( argc != 3 ) 18 cout << "Usage: copyFile infile_name outfile_name" << endl; 19 20 else { 21 ifstream inFile( argv[ 1 ], ios::in ); 22 23 // input file could not be opened 24 if ( !inFile ) { 25 cout << argv[ 1 ] << " could not be opened" << endl; 26 return-1; 27 28 } // end if Notice parameters in main. argv[1] is the input file -- open for reading. fig20_03.cpp(1 of 2)
29 30 ofstream outFile( argv[ 2 ], ios::out ); 31 32 // output file could not be opened 33 if ( !outFile ) { 34 cout << argv[ 2 ] << " could not be opened" << endl; 35 inFile.close(); 36 return-2; 37 38 } // end if 39 40 char c = inFile.get(); // read first character 41 42 while ( inFile ) { 43 outFile.put( c ); // output character 44 c = inFile.get(); // read next character 45 46 } // end while 47 } // end else 48 49 return0; 50 51 } // end main argv[2] is the output file -- open for writing. Read a character from inFile, and write to outFile. Loop stops when EOF reached. fig20_03.cpp(2 of 2)
20.5 Notes on Compiling Multiple-Source-File Programs • Program with multiple source files • Function definition must be entirely in one file • Cannot be split up into multiple files • Global variables accessible to functions in same file • Must be defined in every file they are used • Use extern to access global variable in another file • Indicates variable defined later in file or in another file • Example • int myGlobal; (defined in file1) • extern int myGlobal; (appears in file2)
20.5 Notes on Compiling Multiple-Source-File Programs • Function prototypes • Can be used in other files, extern not needed • Include prototype in each file function used • Compile files together • Prototype indicates function defined later in same file, or in another file • Example: loading header files • #include <cstring> • Contains prototypes of functions • We do not need to know where definitions are
20.5 Notes on Compiling Multiple-Source-File Programs • Keyword static • In context of global variables/functions • Can only be used by functions in same file • Internal linkage • Globals/functions have external linkage by default • Used with utility functions called only in one file • For functions • If defined before used, include static in definition • Otherwise, use with prototype • Makefiles • make - utility to aid compilation and linking • Saves effort of constantly recompiling for minor changes
20.6 Program Termination with exit and atexit • Function exit • Forces program to end • Usually takes EXIT_SUCCESS or EXIT_FAILURE • Symbolic constants (#define) • exit(EXIT_SUCCESS); • Returns value to environment, indicating success or failure • Exact value varies with system
20.6 Program Termination with exit and atexit • Function atexit • Takes pointer to function (function name) • atexit( myFunction ) • Functions must take void, return void • Registers function to run when program ends successfully • When exit called, or when main terminates • atexit does not terminate the program • Can register up to 32 functions • Use multiple atexit calls • Called in reverse order of registration
1 // Fig. 20.4: fig20_04.cpp 2 // Using the exit and atexit functions 3 #include <iostream> 4 5 using std::cout; 6 using std::endl; 7 using std::cin; 8 9 #include <cstdlib> 10 11 void print(); 12 13 int main() 14 { 15 atexit( print ); // register function print 16 17 cout << "Enter 1 to terminate program with function exit" 18 << "\nEnter 2 to terminate program normally\n"; 19 20 int answer; 21 cin >> answer; 22 Register print to be called when the program terminates. print must return void and take no arguments. print will be called if the program ends successfully. fig20_04.cpp(1 of 2)
23 // exit if answer is 1 24 if ( answer == 1 ) { 25 cout << "\nTerminating program with function exit\n"; 26 exit( EXIT_SUCCESS ); 27 28 } // end if 29 30 cout << "\nTerminating program by reaching the end of main" 31 << endl; 32 33 return0; 34 35 } // end main 36 37 // display message before termination 38 void print() 39 { 40 cout << "Executing function print at program termination\n" 41 << "Program terminated" << endl; 42 43 } // end function print Call function exit, passing a symbolic constant. fig20_04.cpp(2 of 2)
Enter 1 to terminate program with function exit Enter 2 to terminate program normally 2 Terminating program by reaching the end of main Executing function print at program termination Program terminated Enter 1 to terminate program with function exit Enter 2 to terminate program normally 1 Terminating program with function exit Executing function print at program termination Program terminated fig20_04.cppoutput (1 of 1)
20.7 The volatile Type Qualifier • volatile qualifier • Indicates variable may be altered outside of program • Variable not under control of program • Compiler cannot perform certain optimizations
20.8 Suffixes for Integer and Floating-Point Constants • C++ has suffixes for constants • Integer suffixes • u or U (unsigned) • l or L (long) • ul or UL (unsignedlong) • Without suffix, uses smallest type that can hold number • Examples: 174u, 1322L, 7364ul • Floating point suffixes • f or F (float) • l or L (long double) • Without suffix, double • Examples: 3.14159L, 1.28f • Incorrect suffix is compiler error
20.9 Signal Handling • Signal • Unexpected event, can terminate program • Interrupts (ctrl-c) • Illegal instructions • Floating-point exceptions (division by zero) • Function signal traps unexpected signals • <csignal> • Takes signal number (symbolic constants defined) • Takes pointer to function (function name) • Signal handler passed signal number • May be required to call signal again inside handler • Depends on system • Reinitialize handler after it handles signal
20.9 Signal Handling • Function raise • Takes signal number • Creates signal
1 // Fig. 20.6: fig20_06.cpp 2 // Using signal handling 3 #include <iostream> 4 5 using std::cout; 6 using std::cin; 7 using std::endl; 8 9 #include <iomanip> 10 11 using std::setw; 12 13 #include <csignal> 14 #include <cstdlib> 15 #include <ctime> 16 17 void signalHandler( int ); 18 19 int main() 20 { 21 signal( SIGINT, signalHandler ); 22 srand( time( 0 ) ); 23 Register signalHandler to deal with SIGINT events. fig20_06.cpp(1 of 3)
24 // create and output random numbers 25 for ( int i = 1; i <= 100; i++ ) { 26 int x = 1 + rand() % 50; 27 28 // raise SIGINT when x is 25 29 if ( x == 25 ) 30 raise( SIGINT ); 31 32 cout << setw( 4 ) << i; 33 34 // output endl when i is a multiple of 10 35 if ( i % 10 == 0 ) 36 cout << endl; 37 38 } // end for 39 40 return0; 41 42 } // end main 43 Note call to function raise. fig20_06.cpp(2 of 3)
44 // handles signal 45 void signalHandler( int signalValue ) 46 { 47 cout << "\nInterrupt signal (" << signalValue 48 << ") received.\n" 49 << "Do you wish to continue (1 = yes or 2 = no)? "; 50 51 int response; 52 53 cin >> response; 54 55 // check for invalid responses 56 while ( response != 1 && response != 2 ) { 57 cout << "(1 = yes or 2 = no)? "; 58 cin >> response; 59 60 } // end while 61 62 // determine if it is time to exit 63 if ( response != 1 ) 64 exit( EXIT_SUCCESS ); 65 66 // call signal and pass it SIGINT and address of signalHandler 67 signal( SIGINT, signalHandler ); 68 69 } // end function signalHandler May be required to reinitialize. fig20_06.cpp(3 of 3)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 Interrupt signal (2) received. Do you wish to continue (1 = yes or 2 = no)? 1 100 1 2 3 4 Interrupt signal (2) received. Do you wish to continue (1 = yes or 2 = no)? 2 fig20_06.cppoutput (1 of 1)
20.10 Dynamic Memory Allocation with calloc and realloc • Dynamic memory allocation • Can create dynamic arrays • Function calloc • void *calloc(size_t nelmt, size_t size) • nelmt - number of elements in array • size - size of each element • Returns pointer to dynamic array • Elements initialized to 0
20.10 Dynamic Memory Allocation with calloc and realloc • Function realloc • Resizes dynamic object • Data not modified if size increased • If shrunk, beginning the same • void *realloc(void *ptr, size_t newSize) • ptr - pointer to object being reallocated • newSize - new size of the object • If ptr == 0, acts like malloc • If newSize == 0 and ptr != 0, memory freed • Returns pointer to reallocated memory (NULL if no space)
20.11 The Unconditional Branch: goto • Unstructured programming • Use when performance crucial • Using break to exit loop • goto statement • goto label; • Program jumps to first statement after label • Label is an identifier and colon (start:) • Quick escape from deeply nested loop • goto start;
1 // Fig. 20.7: fig20_07.cpp 2 // Using goto. 3 #include <iostream> 4 5 using std::cout; 6 using std::endl; 7 8 #include <iomanip> 9 10 using std::left; 11 using std::setw; 12 13 int main() 14 { 15 int count = 1; 16 17 start: // label 18 19 // goto end when count exceeds 10 20 if ( count > 10 ) 21 goto end; 22 23 cout << setw( 2 ) << left << count; 24 ++count; 25 26 // goto start on line 17 27 goto start; Notice declaration of label start Note the format of the goto statement. fig20_07.cpp(1 of 2)
28 29 end: // label 30 31 cout << endl; 32 33 return0; 34 35 } // end main fig20_07.cpp(2 of 2)fig20_07.cppoutput (1 of 1) 1 2 3 4 5 6 7 8 9 10
20.12 Unions • Union • Memory that contains a variety of objects • Data members share space • Only contains one data member at a time • Conserves storage • Only the last data member defined can be accessed • Declaration same as class or struct union Number { int x; float y; } ; Union myObject;
20.12 Unions • Union operations • Assignment to union of same type: = • Taking address: & • Accessing union members: . • Accessing members using pointers: ->
20.12 Unions • Anonymous unions • No type name • Does not create a type; creates an unnamed object • Contains only public data members • Data members accessed like normal variables • Use name, no . or -> required • If declared globally, must be static • Example union { int integer1; double double1; char *charPtr; }; // end anonymous unioninteger1 = 3;
1 // Fig. 20.8: fig20_08.cpp 2 // An example of a union. 3 #include <iostream> 4 5 using std::cout; 6 using std::endl; 7 8 // define union Number 9 union Number { 10 int integer1; 11 double double1; 12 13 }; // end union Number 14 15 int main() 16 { 17 Number value; // union variable 18 19 value.integer1 = 100; // assign 100 to member integer1 20 21 cout << "Put a value in the integer member\n" 22 << "and print both members.\nint: " 23 << value.integer1 << "\ndouble: " << value.double1 24 << endl; 25 Create a named union with two data members. They share the same memory. This will print the integer 100 as a double. The program output is implementation dependent, but will show how ints and doubles are represented differently. fig20_08.cpp(1 of 2)
26 value.double1 = 100.0; // assign 100.0 to member double1 27 28 cout << "Put a value in the floating member\n" 29 << "and print both members.\nint: " 30 << value.integer1 << "\ndouble: " << value.double1 31 << endl; 32 33 return0; 34 35 } // end main fig20_08.cpp(2 of 2)fig20_08.cppoutput (1 of 1) Put a value in the integer member and print both members. int: 100 double: -9.25596e+061 Put a value in the floating member and print both members. int: 0 double: 100
1 // Fig. 20.9: fig20_09.cpp 2 // Using an anonymous union. 3 #include <iostream> 4 5 using std::cout; 6 using std::endl; 7 8 int main() 9 { 10 // declare an anonymous union 11 // members integer1, double1 and charPtr share the same space 12 union { 13 int integer1; 14 double double1; 15 char *charPtr; 16 17 }; // end anonymous union 18 19 // declare local variables 20 int integer2 = 1; 21 double double2 = 3.3; 22 char *char2Ptr = "Anonymous"; 23 Create an anonymous union. The data members can be accessed without using a union name. fig20_09.cpp(1 of 2)
24 // assign value to each union member 25 // successively and print each 26 cout << integer2 << ' '; 27 integer1 = 2; 28 cout << integer1 << endl; 29 30 cout << double2 << ' '; 31 double1 = 4.4; 32 cout << double1 << endl; 33 34 cout << char2Ptr << ' '; 35 charPtr = "union"; 36 cout << charPtr << endl; 37 38 return0; 39 40 } // end main fig20_09.cpp(2 of 2)fig20_09.cppoutput (1 of 1) 1 2 3.3 4.4 Anonymous union
20.13 Linkage Specifications • Can call compiled C functions from C++ program • However, C does not encode function names like C++ • Leads to problems linking • Linkage specifications • To link properly, tell compiler that function compiled in C • For single functions extern "C" function prototype • For multiple functions extern "C" { function prototypes }