Contained WithinFind More DocumentationFeatured Support Resources | Descargar este libro en PDF (1976 KB)
Part III LibrariesChapter 12 Using LibrariesLibraries provide a way to share code among several applications and a way to reduce the complexity of very large applications. The C++ compiler gives you access to a variety of libraries. This chapter explains how to use these libraries. 12.1 The C LibrariesThe Solaris operating system comes with several libraries installed in /usr/lib. Most of these libraries have a C interface. Of these, the libc and libm, libraries are linked by the CC driver by default. The library libthread is linked if you use the–mt option. To link any other system library, use the appropriate –l option at link time. For example, to link the libdemangle library, pass –ldemangle on the CC command line at link time:
The C++ compiler has its own runtime support libraries. All C++ applications are linked to these libraries by the CC driver. The C++ compiler also comes with several other useful libraries, as explained in the following section. 12.2 Libraries Provided With the C++ CompilerSeveral libraries are shipped with the C++ compiler. Some of these libraries are available only in compatibility mode (-compat=4), some are available only in the standard mode (–compat=5), and some are available in both modes. The libgc and libdemangle libraries have a C interface and can be linked to an application in either mode. The following table lists the libraries that are shipped with the C++ compiler and the modes in which they are available. Table 12–1 Libraries Shipped With the C++ Compiler
Note – Do not redefine or modify any of the configuration macros for STLport, Rogue Wave or Sun Microsystems C++ libraries. The libraries are configured and built in a way that works with the C++ compiler. libCstd and Tool.h++ are configured to inter-operate so modifying the configuration macros results in programs that will not compile, will not link, or do not run properly. 12.2.1 C++ Library DescriptionsA brief description of each of these libraries follows.
If your compiler software is not installed in the /opt directory, ask your system administrator for the equivalent path on your system.
12.2.2 Accessing the C++ Library Man PagesThe man pages associated with the libraries described in this section are located in:
To access these man pages, ensure that your MANPATH includes /opt/SUNWspro/man (or the equivalent path on your system for the compiler software). To access man pages for the C++ libraries, type:
To access man pages for version 4.2 of the C++ libraries, type:
You can also access the man pages by pointing your browser to:
12.2.3 Default C++ LibrariesSome of the C++ libraries are linked by default by the CC driver, while others need to be linked explicitly. In the standard mode, the following libraries are linked by default by the CC driver: In compatibility mode (-compat), the following libraries are linked by default: -lC -lm -lc See A.2.49 -library=l[,l...] for more information. 12.3 Related Library OptionsThe CC driver provides several options to help you use libraries.
By default, CC links various sets of system libraries depending on the command line options. If you specify -xnolib (or -nolib), CC links only those libraries that are specified explicitly with the -l option on the command line. (When -xnolib or -nolib is used, the -library option is ignored, if present.) The –R option allows you to build dynamic library search paths into the executable file. At execution time, the runtime linker searches these paths for the shared libraries needed by the application. The CC driver passes– R/opt/SUNWspro/lib to ld by default (if the compiler is installed in the standard location). You can use -norunpath to disable building the default path for shared libraries into the executable. 12.4 Using Class LibrariesGenerally, two steps are involved in using a class library:
12.4.1 The iostream LibraryThe C++ compiler provides two implementations of iostreams:
If you have existing C++ sources, your code might look like the following example, which uses classic iostreams.
The following command compiles in compatibility mode and links prog1.cc into an executable program called prog1. The classic iostream library is part of libC, which is linked by default in compatibility mode.
The next example uses standard iostreams.
The following command compiles and links prog2.cc into an executable program called prog2. The program is compiled in standard mode and libCstd, which includes the standard iostream library, is linked by default.
For more information about libCstd, see Caveats:. For more information about libiostream, see 13.3.1 Redistribution and Supported STLport Libraries. For a full discussion of compilation modes, see the C++ Migration Guide. 12.4.2 The complex LibraryThe standard library provides a templatized complex library that is similar to the complex library provided with the C++ 4.2 compiler. If you compile in standard mode, you must use <complex> instead of <complex.h>. You cannot use <complex> in compatibility mode. In compatibility mode, you must explicitly ask for the complex library when linking. In standard mode, the complex library is included in libCstd, and is linked by default. There is no complex.h header for standard mode. In C++ 4.2, “complex” is the name of a class, but in standard C++, “complex” is the name of a template. It is not possible to provide typedefs that allow old code to work unchanged. Therefore, code written for 4.2 that uses complex numbers will need some straightforward editing to work with the standard library. For example, the following code was written for 4.2 and will compile in compatibility mode.
The following example compiles and links ex1.cc in compatibility mode, and then executes the program.
Here is ex1.cc rewritten as ex2.cc to compile in standard mode:
The following example compiles and links the rewritten ex2.cc in standard mode, and then executes the program.
For more information about using the complex arithmetic library, see Table 14–4. 12.4.3 Linking C++ LibrariesThe following table shows the compiler options for linking the C++ libraries. See A.2.49 -library=l[,l...] for more information. Table 12–2 Compiler Options for Linking C++ Libraries
12.5 Statically Linking Standard LibrariesThe CC driver links in shared versions of several libraries by default, including libc and libm, by passing a -llib option for each of the default libraries to the linker. (See 12.2.3 Default C++ Libraries for the list of default libraries for compatibility mode and standard mode.) If you want any of these default libraries to be linked statically, you can use the -library option along with the –staticlib option to link a C++ library statically. This alternative is much easier than the one described earlier. For example:
In this example, the -library option is not explicitly included in the command. In this case the -library option is not necessary because the default setting for -library is Cstd,Crun in standard mode (the default mode). Alternately, you can use the -xnolib compiler option. With the -xnolib option, the driver does not pass any -l options to ld; you must pass these options yourself. The following example shows how you would link statically with libCrun, and dynamically with libm, and libc in the Solaris 8, or Solaris 9 operating systems:
The order of the -l options is important. The– lCstd,– lCrun, and -lm options appear before -lc. Some CC options link to other libraries. These library links are also suppressed by -xnolib. For example, using the -mt option causes the CC driver to pass -lthread to ld. However, if you use both–mt and –xnolib, the CC driver does not pass-lthread to ld. See A.2.149 –xnolib for more information. See Linker and Libraries Guide for more information about ld. 12.6 Using Shared LibrariesThe following shared libraries are included with the C++ compiler:
The occurrence of each shared object linked with the program is recorded in the resulting executable (a.out file); this information is used by ld.so to perform dynamic link editing at runtime. Because the work of incorporating the library code into an address space is deferred, the runtime behavior of the program using a shared library is sensitive to an environment change—that is, moving a library from one directory to another. For example, if your program is linked with libcomplex.so.5 in /opt/SUNWspro/lib, and the libcomplex.so.5 library is later moved into /opt2/SUNWspro/lib, the following message is displayed when you run the binary code:
You can still run the old binary code without recompiling it by setting the environment variable LD_LIBRARY_PATH to the new library directory. In a C shell:
In a Bourne shell:
Note – release is specific for each release of the compiler software. The LD_LIBRARY_PATH has a list of directories, usually separated by colons. When you run a C++ program, the dynamic loader searches the directories in LD_LIBRARY_PATH before it searches the default directories. Use the ldd command as shown in the following example to see which libraries are linked dynamically in your executable:
This step should rarely be necessary, because the shared libraries are seldom moved. Note – When shared libraries are opened with dlopen, RTLD_GLOBAL must be used for exceptions to work. See Linker and Libraries Guide for more information on using shared libraries. 12.7 Replacing the C++ Standard LibraryReplacing the standard library that is distributed with the compiler is risky, and good results are not guaranteed. The basic operation is to disable the standard headers and library supplied with the compiler, and to specify the directories where the new header files and library are found, as well as the name of the library itself. The compiler supports the STLport implementation of the standard library. See 13.3 STLport for more information. 12.7.1 What Can Be ReplacedYou can replace most of the standard library and its associated headers. The replaced library is libCstd, and the associated headers are listed in the following table:
The replaceable part of the library consists of what is loosely known as “STL”, plus the string classes, the iostream classes, and their helper classes. Because these classes and headers are interdependent, replacing just a portion of them is unlikely to work. You should replace all of the headers and all of libCstd if you replace any part. 12.7.2 What Cannot Be ReplacedThe standard headers <exception>, <new>, and <typeinfo> are tied tightly to the compiler itself and to libCrun, and cannot reliably be replaced. The library libCrun contains many “helper” functions that the compiler depends on, and cannot be replaced. The 17 standard headers inherited from C (<stdlib.h>, <stdio.h>, <string.h>, and so forth) are tied tightly to the Solaris operating system and the basic Solaris runtime library libc, and cannot reliably be replaced. The C++ versions of those headers (<cstdlib>, <cstdio>, <cstring>, and so forth) are tied tightly to the basic C versions and cannot reliably be replaced. 12.7.3 Installing the Replacement LibraryTo install the replacement library, you must first decide on the locations for the replacement headers and on the replacement for libCstd. For purposes of discussion, assume the headers are placed in /opt/mycstd/include and the library is placed in /opt/mycstd/lib. Assume the library is called libmyCstd.a. (It is often convenient if the library name starts with “lib”.) 12.7.4 Using the Replacement LibraryOn each compilation, use the -I option to point to the location where the headers are installed. In addition, use the -library=no%Cstd option to prevent finding the compiler’s own versions of the libCstd headers. For example:
During compiling, the -library=no%Cstd option prevents searching the directory where the compiler’s own version of these headers is located. On each program or library link, use the -library=no%Cstd option to prevent finding the compiler’s own libCstd, the -L option to point to the directory where the replacement library is, and the -l option to specify the replacement library. Example:
Alternatively, you can use the full path name of the library directly, and omit using the -L and -l options. For example:
During linking, the -library=no%Cstd option prevents linking the compiler’s own version of libCstd. 12.7.5 Standard Header ImplementationC has 17 standard headers (<stdio.h>, <string.h>, <stdlib.h>, and others). These headers are delivered as part of the Solaris operating system, in the directory /usr/include. C++ has those same headers, with the added requirement that the various declared names appear in both the global namespace and in namespace std. On versions of the Solaris operating system prior to version 8, the C++ compiler supplies its own versions of these headers instead of replacing those in the /usr/include directory. C++ also has a second version of each of the C standard headers (<cstdio>, <cstring>, and <cstdlib>, and others) with the various declared names appearing only in namespace std. Finally, C++ adds 32 of its own standard headers (<string>, <utility>, <iostream>, and others). The obvious implementation of the standard headers would use the name found in C++ source code as the name of a text file to be included. For example, the standard headers <string> (or <string.h>) would refer to a file named string (or string.h) in some directory. That obvious implementation has the following drawbacks:
To solve these problems, the compiler include directory contains a file with the same name as the header, along with a symbolic link to it that has the unique suffix .SUNWCCh (SUNW is the prefix for all compiler-related packages, CC is the C++ compiler, and h is the usual suffix for header files). When you specify <string>, the compiler rewrites it to <string.SUNWCCh> and searches for that name. The suffixed name will be found only in the compiler’s own include directory. If the file so found is a symbolic link (which it normally is), the compiler dereferences the link exactly once and uses the result (string in this case) as the file name for error messages and debugger references. The compiler uses the suffixed name when emitting file dependency information. The name rewriting occurs only for the two forms of the 17 standard C headers and the 32 standard C++ headers, only when they appear in angle brackets and without any path specified. If you use quotes instead of angle brackets, specify any path components, or specify some other header, no rewriting occurs. The following table illustrates common situations. Table 12–3 Header Search Examples
If the compiler does not find header.SUNWCCh, the compiler restarts the search looking for the name as provided in the #include directive. For example, given the directive #include <string>, the compiler attempts to find a file named string.SUNWCCh. If that search fails, the compiler looks for a file named string. 12.7.5.1 Replacing Standard C++ HeadersBecause of the search algorithm described in 12.7.5 Standard Header Implementation, you do not need to supply SUNWCCh versions of the replacement headers described in 12.7.3 Installing the Replacement Library. But you might run into some of the described problems. If so, the recommended solution is to add symbolic links having the suffix .SUNWCCh for each of the unsuffixed headers. That is, for file utility, you would run the command
When the compiler looks first for utility.SUNWCCh, it will find it, and not be confused by any other file or directory called utility. 12.7.5.2 Replacing Standard C HeadersReplacing the standard C headers is not supported. If you nevertheless wish to provide your own versions of standard headers, the recommended procedure is as follows:
For example, suppose you have replacements for <stdio.h> and <cstdio>. Put the files stdio.h and cstdio in directory /myproject/myhdr. In that directory, run these commands:
Use the option -I/myproject/mydir on every compilation. Caveats:
Chapter 13 Using The C++ Standard LibraryWhen compiling in default (standard) mode, the compiler has access to the complete library specified by the C++ standard. The library components include what is informally known as the Standard Template Library (STL), as well as the following components.
The term STL does not have a formal definition, but is usually understood to include containers, iterators, and algorithms. The following subset of the standard library headers can be thought of as comprising the STL.
The C++ standard library (libCstd) is based on the RogueWaveTM Standard C++ Library, Version 2. This library is available only for the default mode (-compat=5) of the compiler and is not supported with use of the -compat[=4] option. The C++ compiler also supports STLport’s Standard Library implementation version 4.5.3. libCstd is still the default library, but STLport’s product is available as an alternative. See 13.3 STLport for more information. If you need to use your own version of the C++ standard library instead of one of the versions that is supplied with the compiler, you can do so by specifying the -library=no%Cstd option. Replacing the standard library that is distributed with the compiler is risky, and good results are not guaranteed. For more information, see 12.7 Replacing the C++ Standard Library. For details about the standard library, see the Standard C++ Library User’s Guide and the Standard C++ Class Library Reference. Accessing Sun Studio Documentation in “Before You Begin” at the front of this book contains information about accessing this documentation. For a list of available books about the C++ standard library see Commercially Available Books in “Before You Begin.” 13.1 C++ Standard Library Header FilesTable 13–1 lists the headers for the complete standard library along with a brief description of each. Table 13–1 C++ Standard Library Header Files
13.2 C++ Standard Library Man PagesTable 13–2 lists the documentation available for each of the components of the standard library. Table 13–2 Man Pages for C++ Standard Library
13.3 STLportUse the STLport implementation of the standard library if you wish to use an alternative standard library to libCstd. You can issue the following compiler option to turn off libCstd and use the STLport library instead:
See A.2.49 -library=l[,l...] for more information. This release includes both a static archive called libstlport.a and a dynamic library called libstlport.so. Consider the following information before you decide whether or not you are going to use the STLport implementation:
13.3.1 Redistribution and Supported STLport LibrariesSee the Runtime Libraries Readme for a list of libraries and object files that you can redistribute with your executables or libraries under the terms of the End User Object Code License. The C++ section of this readme lists which version of the STLport .so this release of the compiler supports. This readme is available as part of the installed product. To view the HTML version of this readme, point your browser to the default installation directory: file:/opt/SUNWspro/docs/index.html Note – If your product software is not installed in the default directory, ask your system administrator for the equivalent path on your system. The following test case does not compile with STLport because the code in the test case makes unportable assumptions about the library implementation. In particular, it assumes that either <vector> or <iostream> automatically include <iterator>, which is not a valid assumption.
To fix the problem, include <iterator> in the source. Chapter 14 Using the Classic iostream LibraryC++, like C, has no built-in input or output statements. Instead, I/O facilities are provided by a library. The C++ compiler provides both the classic implementation and the ISO standard implementation of the iostream classes.
This chapter provides an introduction to the classic iostream library and provides examples of its use. This chapter does not provide a complete description of the iostream library. See the iostream library man pages for more details. To access the classic iostream man pages type:man -s 3CC4name 14.1 Predefined iostreamsThere are four predefined iostreams: The predefined iostreams are fully buffered, except for cerr. See 14.3.1 Output Using iostream and 14.3.2 Input Using iostream. 14.2 Basic Structure of iostream InteractionBy including the iostream library, a program can use any number of input or output streams. Each stream has some source or sink, which may be one of the following:
A stream can be restricted to input or output, or a single stream can allow both input and output. The iostream library implements these streams using two processing layers.
Standard input, output, and error are handled by special class objects derived from class istream or ostream. The ifstream, ofstream, and fstream classes, which are derived from istream, ostream, and iostream respectively, handle input and output with files. The istrstream, ostrstream, and strstream classes, which are derived from istream, ostream, and iostream respectively, handle input and output to and from arrays of characters. When you open an input or output stream, you create an object of one of these types, and associate the streambuf member of the stream with a device or file. You generally do this association through the stream constructor, so you don’t work with the streambuf directly. The iostream library predefines stream objects for the standard input, standard output, and error output, so you don’t have to create your own objects for those streams. You use operators or iostream member functions to insert data into a stream (output) or extract data from a stream (input), and to control the format of data that you insert or extract. When you want to insert and extract a new data type—one of your classes—you generally overload the insertion and extraction operators. 14.3 Using the Classic iostream LibraryTo use routines from the classic iostream library, you must include the header files for the part of the library you need. The header files are described in the following table. Table 14–1 iostream Routine Header Files
You usually do not need all of these header files in your program. Include only the ones that contain the declarations you need. In compatibility mode (-compat[=4]), the classic iostream library is part of libC, and is linked automatically by the CC driver. In standard mode (the default), libiostream contains the classic iostream library. 14.3.1 Output Using iostreamOutput using iostream usually relies on the overloaded left-shift operator (<<) which, in the context of iostream, is called the insertion operator. To output a value to standard output, you insert the value in the predefined output stream cout. For example, given a value someValue, you send it to standard output with a statement like:
The insertion operator is overloaded for all built-in types, and the value represented by someValue is converted to its proper output representation. If, for example, someValue is a float value, the << operator converts the value to the proper sequence of digits with a decimal point. Where it inserts float values on the output stream, << is called the float inserter. In general, given a type X, << is called the X inserter. The format of output and how you can control it is discussed in the ios(3CC4) man page. The iostream library does not support user-defined types. If you define types that you want to output in your own way, you must define an inserter (that is, overload the << operator) to handle them correctly. The << operator can be applied repetitively. To insert two values on cout, you can use a statement like the one in the following example:
The output from the above example will show no space between the two values. So you may want to write the code this way:
The << operator has the precedence of the left shift operator (its built-in meaning). As with other operators, you can always use parentheses to specify the order of action. It is often a good idea to use parentheses to avoid problems of precedence. Of the following four statements, the first two are equivalent, but the last two are not.
14.3.1.1 Defining Your Own Insertion OperatorThe following example defines a string class:
The insertion and extraction operators must in this case be defined as friends because the data part of the string class is private.
Here is the definition of operator<< overloaded for use with strings.
operator<< takes ostream& (that is, a reference to an ostream) as its first argument and returns the same ostream, making it possible to combine insertions in one statement. 14.3.1.2 Handling Output ErrorsGenerally, you don’t have to check for errors when you overload operator<< because the iostream library is arranged to propagate errors. When an error occurs, the iostream where it occurred enters an error state. Bits in the iostream’s state are set according to the general category of the error. The inserters defined in iostream ignore attempts to insert data into any stream that is in an error state, so such attempts do not change the iostream’s state. In general, the recommended way to handle errors is to periodically check the state of the output stream in some central place. If there is an error, you should handle it in some way. This chapter assumes that you define a function error, which takes a string and aborts the program. error is not a predefined function. See 14.3.9 Handling Input Errors for an example of an error function. You can examine the state of an iostream with the operator !,which returns a nonzero value if the iostream is in an error state. For example:
There is another way to test for errors. The ios class defines operator void *(), so it returns a NULL pointer when there is an error. You can use a statement like:
You can also use the function good, a member of ios:
The error bits are declared in the enum:
For details on the error functions, see the iostream man pages. 14.3.1.3 FlushingAs with most I/O libraries, iostream often accumulates output and sends it on in larger and generally more efficient chunks. If you want to flush the buffer, you simply insert the special value flush. For example:
flush is an example of a kind of object known as a manipulator, which is a value that can be inserted into an iostream to have some effect other than causing output of its value. It is really a function that takes an ostream& or istream& argument and returns its argument after performing some actions on it (see 14.7 Manipulators). 14.3.1.4 Binary OutputTo obtain output in the raw binary form of a value, use the member function write as shown in the following example. This example shows the output in the raw binary form of x.
The previous example violates type discipline by converting &x to char*. Doing so is normally harmless, but if the type of x is a class with pointers, virtual member functions, or one that requires nontrivial constructor actions, the value written by the above example cannot be read back in properly. 14.3.2 Input Using iostreamInput using iostream is similar to output. You use the extraction operator >> and you can string together extractions the way you can with insertions. For example:
This statement gets two values from standard input. As with other overloaded operators, the extractors used depend on the types of a and b (and two different extractors are used if a and b have different types). The format of input and how you can control it is discussed in some detail in the ios(3CC4) man page. In general, leading whitespace characters (spaces, newlines, tabs, form-feeds, and so on) are ignored. 14.3.3 Defining Your Own Extraction OperatorsWhen you want input for a new type, you overload the extraction operator for it, just as you overload the insertion operator for output. Class string defines its extraction operator in the following code example: Example 14–1 string Extraction Operator
The get function reads characters from the input stream istr and stores them in holder until maxline-1 characters have been read, or a new line is encountered, or EOF, whichever happens first. The data in holder is then null-terminated. Finally, the characters in holder are copied into the target string. By convention, an extractor converts characters from its first argument (in this case, istream& istr), stores them in its second argument, which is always a reference, and returns its first argument. The second argument must be a reference because an extractor is meant to store the input value in its second argument. 14.3.4 Using the char* ExtractorThis predefined extractor is mentioned here because it can cause problems. Use it like this:
This extractor skips leading whitespace and extracts characters and copies them to x until it reaches another whitespace character. It then completes the string with a terminating null (0) character. Be careful, because input can overflow the given array. You must also be sure the pointer points to allocated storage. For example, here is a common error:
There is no telling where the input data will be stored, and it may cause your program to abort. 14.3.5 Reading Any Single CharacterIn addition to using the char extractor, you can get a single character with either form of the get member function. For example:
Note – Unlike the other extractors, the char extractor does not skip leading whitespace. Here is a way to skip only blanks, stopping on a tab, newline, or any other character:
14.3.6 Binary InputIf you need to read binary values (such as those written with the member function write), you can use the read member function. The following example shows how to input the raw binary form of x using the read member function, and is the inverse of the earlier example that uses write.
14.3.7 Peeking at InputYou can use the peek member function to look at the next character in the stream without extracting it. For example:
14.3.8 Extracting WhitespaceBy default, the iostream extractors skip leading whitespace. You can turn off the skip flag to prevent this from happening. The following example turns off whitespace skipping from cin, then turns it back on:
You can use the iostream manipulator ws to remove leading whitespace from the iostream, whether or not skipping is enabled. The following example shows how to remove the leading whitespace from iostream istr:
14.3.9 Handling Input ErrorsBy convention, an extractor whose first argument has a nonzero error state should not extract anything from the input stream and should not clear any error bits. An extractor that fails should set at least one error bit. As with output errors, you should check the error state periodically and take some action, such as aborting, when you find a nonzero state. The ! operator tests the error state of an iostream. For example, the following code produces an input error if you type alphabetic characters for input:
Class ios has member functions that you can use for error handling. See the man pages for details. 14.3.10 Using iostreams With stdioYou can use stdio with C++ programs, but problems can occur when you mix iostreams and stdio in the same standard stream within a program. For example, if you write to both stdout and cout, independent buffering occurs and produces unexpected results. The problem is worse if you input from both stdin and cin, since independent buffering may turn the input into trash. To eliminate this problem with standard input, standard output and standard error, use the following instruction before performing any input or output. It connects all the predefined iostreams with the corresponding predefined stdio FILEs.
Such a connection is not the default because there is a significant performance penalty when the predefined streams are made unbuffered as part of the connection. You can use both stdio and iostreams in the same program applied to different files. That is, you can write to stdout using stdio routines and write to other files attached to iostreams. You can open stdio FILEs for input and also read from cin so long as you don’t also try to read from stdin. 14.4 Creating iostreamsTo read or write a stream other than the predefined iostreams, you need to create your own iostream. In general, that means creating objects of types defined in the iostream library. This section discusses the various types available. 14.4.1 Dealing With Files Using Class fstreamDealing with files is similar to dealing with standard input and standard output; classes ifstream, ofstream, and fstream are derived from classes istream, ostream, and iostream, respectively. As derived classes, they inherit the insertion and extraction operations (along with the other member functions) and also have members and constructors for use with files. Include the file fstream.h to use any of the fstreams. Use an ifstream when you only want to perform input, an ofstream for output only, and an fstream for a stream on which you want to perform both input and output. Use the name of the file as the constructor argument. For example, copy the file thisFile to the file thatFile as in the following example:
This code:
14.4.1.1 Open ModeThe mode is constructed by or-ing bits from the enumerated type open_mode, which is a public type of class ios and has the definition:
Note – The binary flag is not needed on UNIX, but is provided for compatibility with systems that do need it. Portable code should use the binary flag when opening binary files. You can open a file for both input and output. For example, the following code opens file someName for both input and output, attaching it to the fstream variable inoutFile.
14.4.1.2 Declaring an fstream Without Specifying a FileYou can declare an fstream without specifying a file and open the file later. For example, the following creates the ofstream toFile for writing.
14.4.1.3 Opening and Closing FilesYou can close the fstream and then open it with another file. For example, to process a list of files provided on the command line:
14.4.1.4 Opening a File Using a File DescriptorIf you know a file descriptor, such as the integer 1 for standard output, you can open it like this:
When you open a file by providing its name to one of the fstream constructors or by using the open function, the file is automatically closed when the fstream is destroyed (by a delete or when it goes out of scope). When you attach a file to an fstream, it is not automatically closed. 14.4.1.5 Repositioning Within a FileYou can alter the reading and writing position in a file. Several tools are supplied for this purpose.
For example, given an fstream aFile:
seekg (seekp) can take one or two parameters. When it has two parameters, the first is a position relative to the position indicated by the seek_dir value given as the second parameter. For example:
moves to 10 bytes from the end while
moves to 10 bytes forward from the current position. Note – Arbitrary seeks on text streams are not portable, but you can always return to a previously saved streampos value. 14.5 Assignment of iostreamsiostreams does not allow assignment of one stream to another. The problem with copying a stream object is that there are then two versions of the state information, such as a pointer to the current write position within an output file, which can be changed independently. As a result, problems could occur. 14.6 Format ControlFormat control is discussed in detail in the in the man page ios(3CC4). 14.7 ManipulatorsManipulators are values that you can insert into or extract from iostreams to have special effects. Parameterized manipulators are manipulators that take one or more parameters. Because manipulators are ordinary identifiers, and therefore use up possible names, iostream doesn’t define them for every possible function. A number of manipulators are discussed with member functions in other parts of this chapter. There are 13 predefined manipulators, as described in Table 14–2. When using that table, assume the following:
To use predefined manipulators, you must include the file iomanip.h in your program. You can define your own manipulators. There are two basic types of manipulator:
14.7.1 Using Plain ManipulatorsA plain manipulator is a function that:
The shift operators taking (a pointer to) such a function are predefined for iostreams, so the function can be put in a sequence of input or output operators. The shift operator calls the function rather than trying to read or write a value. An example of a tab manipulator that inserts a tab in an ostream is:
This is an elaborate way to achieve the following:
The following code is another example, which cannot be accomplished with a simple constant. Suppose you want to turn whitespace skipping on and off for an input stream. You can use separate calls to ios::setf and ios::unsetf to turn the skipws flag on and off, or you could define two manipulators.
14.7.2 Parameterized ManipulatorsOne of the parameterized manipulators that is included in iomanip.h is setfill. setfill sets the character that is used to fill out field widths. It is implemented as shown in the following example:
A parameterized manipulator is implemented in two parts:
Several classes are defined in the header file iomanip.h. Each class holds the address of a manipulator function and the value of one parameter. The iomanip classes are described in the man page manip(3CC4). The previous example uses the smanip_int class, which works with an ios. Because it works with an ios, it also works with an istream and an ostream. The previous example also uses a second parameter of type int. The applicator creates and returns a class object. In the previous code example the class object is an smanip_int, and it contains the manipulator and the int argument to the applicator. The iomanip.h header file defines the shift operators for this class. When the applicator function setfill appears in a sequence of input or output operations, the applicator function is called, and it returns a class. The shift operator acts on the class to call the manipulator function with its parameter value, which is stored in the class. In the following example, the manipulator print_hex:
The class omanip_long is used because this code example is for output only, and it operates on a long rather than an int:
14.8 Strstreams: iostreams for ArraysSee the strstream(3CC4) man page. 14.9 Stdiobufs: iostreams for stdio FilesSee the stdiobuf(3CC4) man page. 14.10 Streambufsiostreams are the formatting part of a two-part (input or output) system. The other part of the system is made up of streambufs, which deal in input or output of unformatted streams of characters. You usually use streambufs through iostreams, so you don’t have to worry about the details of streambufs. You can use streambufs directly if you choose to, for example, if you need to improve efficiency or to get around the error handling or formatting built into iostreams. 14.10.1 Working With StreambufsA streambuf consists of a stream or sequence of characters and one or two pointers into that sequence. Each pointer points between two characters. (Pointers cannot actually point between characters, but it is helpful to think of them that way.) There are two kinds of streambuf pointers:
A streambuf can have one or both of these pointers. 14.10.1.1 Position of PointersThe positions of the pointers and the contents of the sequences can be manipulated in various ways. Whether or not both pointers move when manipulated depends on the kind of streambuf used. Generally, with queue-like streambufs, the get and put pointers move independently; with file-like streambufs the get and put pointers always move together. A strstream is an example of a queue-like stream; an fstream is an example of a file-like stream. 14.10.2 Using StreambufsYou never create an actual streambuf object, but only objects of classes derived from class streambuf. Examples are filebuf and strstreambuf, which are described in man pages filebuf(3CC4) and ssbuf(3), respectively. Advanced users may want to derive their own classes from streambuf to provide an interface to a special device or to provide other than basic buffering. Man pages sbufpub(3CC4) and sbufprot(3CC4) discuss how to do this. Apart from creating your own special kind of streambuf, you may want to access the streambuf associated with an iostream to access the public member functions, as described in the man pages referenced above. In addition, each iostream has a defined inserter and extractor which takes a streambuf pointer. When a streambuf is inserted or extracted, the entire stream is copied. Here is another way to do the file copy discussed earlier, with the error checking omitted for clarity:
We open the input and output files as before. Every iostream class has a member function rdbuf that returns a pointer to the streambuf object associated with it. In the case of an fstream, the streambuf object is type filebuf. The entire file associated with fromFile is copied (inserted into) the file associated with toFile. The last line could also be written like this:
The source file is then extracted into the destination. The two methods are entirely equivalent. 14.11 iostream Man PagesA number of C++ man pages give details of the iostream library. The following table gives an overview of what is in each man page. To access a classic iostream library man page, type:
14.12 iostream TerminologyThe iostream library descriptions often use terms similar to terms from general programming, but with specialized meanings. The following table defines these terms as they are used in discussing the iostream library. Table 14–4 iostream Terminology
Chapter 15 Using the Complex Arithmetic LibraryComplex numbers are numbers made up of a real part and an imaginary part. For example: 3.2 + 4i 1 + 3i 1 + 2.3i In the degenerate case, 0 + 3i is an entirely imaginary number generally written as 3i, and 5 + 0i is an entirely real number generally written as 5. You can represent complex numbers using the complex data type. Note – The complex arithmetic library ( libcomplex) is available only for compatibility mode ( -compat[ =4]). In standard mode (the default mode), complex number classes with similar functionality are included with the C++ Standard Library libCstd. 15.1 The Complex LibraryThe complex arithmetic library implements a complex number data type as a new data type and provides:
Complex numbers can also be represented as an absolute value (or magnitude) and an argument (or angle). The library provides functions to convert between the real and imaginary (Cartesian) representation and the magnitude and angle (polar) representation. The complex conjugate of a number has the opposite sign in its imaginary part. 15.1.1 Using the Complex LibraryTo use the complex library, include the header file complex.h in your program, and compile and link with the -library=complex option. 15.2 Type complexThe complex arithmetic library defines one class: class complex. An object of class complex can hold a single complex number. The complex number is constructed of two parts:
The value of an object of class complex is a pair of double values. The first value represents the real part; the second value represents the imaginary part. 15.2.1 Constructors of Class complexThere are two constructors for complex. Their definitions are:
If you declare a complex variable without specifying parameters, the first constructor is used and the variable is initialized, so that both parts are 0. The following example creates a complex variable whose real and imaginary parts are both 0:
You can give either one or two parameters. In either case, the second constructor is used. When you give only one parameter, that parameter is taken as the value for the real part and the imaginary part is set to 0. For example:
creates a complex variable with the following value:
If you give two values, the first value is taken as the value of the real part and the second as the value of the imaginary part. For example:
creates a complex variable with the following value:
You can also create a complex number using the polar function, which is provided in the complex arithmetic library (see 15.3 Mathematical Functions). The polar function creates a complex value given the polar coordinates magnitude and angle. There is no destructor for type complex. 15.2.2 Arithmetic OperatorsThe complex arithmetic library defines all the basic arithmetic operators. Specifically, the following operators work in the usual way and with the usual precedence: + - / * = The subtraction operator (-) has its usual binary and unary meanings. In addition, you can use the following operators in the usual way:
However, the preceding four operators do not produce values that you can use in expressions. For example, the following expressions do not work:
You can also use the equality operator (==) and the inequality operator (!=) in their regular meaning. When you mix real and complex numbers in an arithmetic expression, C++ uses the complex operator function and converts the real values to complex values. 15.3 Mathematical FunctionsThe complex arithmetic library provides a number of mathematical functions. Some are peculiar to complex numbers; the rest are complex-number versions of functions in the standard C mathematical library. All of these functions produce a result for every possible argument. If a function cannot produce a mathematically acceptable result, it calls complex_error and returns some suitable value. In particular, the functions try to avoid actual overflow and call complex_error with a message instead. The following tables describe the remainder of the complex arithmetic library functions. Note – The implementation of the sqrt and atan2 functions is aligned with the C99 csqrt Annex G specification. Table 15–1 Complex Arithmetic Library Functions
Table 15–2 Complex Mathematical and Trigonometric Functions
15.4 Error HandlingThe complex library has these definitions for error handling:
The external variable errno is the global error state from the C library. errno can take on the values listed in the standard header errno.h (see the man page perror(3)). No function sets errno to zero, but many functions set it to other values. To determine whether a particular operation fails:
The function complex_error takes a reference to type c_exception and is called by the following complex arithmetic library functions:
The default version of complex_error returns zero. This return of zero means that the default error handling takes place. You can provide your own replacement function complex_error that performs other error handling. Error handling is described in the man page cplxerr(3CC4). Default error handling is described in the man pages cplxtrig(3CC4) and cplxexp(3CC4) It is also summarized in the following table.
15.5 Input and OutputThe complex arithmetic library provides default extractors and inserters for complex numbers, as shown in the following example:
For basic information on extractors and inserters, see 14.2 Basic Structure of iostream Interaction and 14.3.1 Output Using iostream. For input, the complex extractor >> extracts a pair of numbers (surrounded by parentheses and separated by a comma) from the input stream and reads them into a complex object. The first number is taken as the value of the real part; the second as the value of the imaginary part. For example, given the declaration and input statement:
and the input (3.45, 5), the value of x is equivalent to 3.45 + 5.0i. The reverse is true for inserters. Given complex x(3.45, 5), cout<<x prints (3.45, 5). The input usually consists of a pair of numbers in parentheses separated by a comma; white space is optional. If you provide a single number, with or without parentheses and white space, the extractor sets the imaginary part of the number to zero. Do not include the symbol i in the input text. The inserter inserts the values of the real and imaginary parts enclosed in parentheses and separated by a comma. It does not include the symbol i. The two values are treated as doubles. 15.6 Mixed-Mode ArithmeticType complex is designed to fit in with the built-in arithmetic types in mixed-mode expressions. Arithmetic types are silently converted to type complex, and there are complex versions of the arithmetic operators and most mathematical functions. For example:
The expression b+i is mixed-mode. Integer i is converted to type complex via the constructor complex::complex(double,double=0), the integer first being converted to type double. The result is to be divided by y, a double, so y is also converted to complex and the complex divide operation is used. The quotient is thus type complex, so the complex sine routine is called, yielding another complex result, and so on. Not all arithmetic operations and conversions are implicit, or even defined, however. For example, complex numbers are not well-ordered, mathematically speaking, and complex numbers can be compared for equality only.
Similarly, there is no automatic conversion from type complex to any other type, because the concept is not well-defined. You can specify whether you want the real part, imaginary part, or magnitude, for example.
15.7 EfficiencyThe design of the complex class addresses efficiency concerns. The simplest functions are declared inline to eliminate function call overhead. Several overloaded versions of functions are provided when that makes a difference. For example, the pow function has versions that take exponents of type double and int as well as complex, since the computations for the former are much simpler. The standard C math library header math.h is included automatically when you include complex.h. The C++ overloading rules then result in efficient evaluation of expressions like this:
In this example, the standard math function sqrt(double) is called, and the result is converted to type complex, rather than converting to type complex first and then calling sqrt(complex). This result falls right out of the overload resolution rules, and is precisely the result you want. 15.8 Complex Man PagesThe remaining documentation of the complex arithmetic library consists of the man pages listed in the following table. Table 15–3 Man Pages for Type complex
Chapter 16 Building LibrariesThis chapter explains how to build your own libraries. 16.1 Understanding LibrariesLibraries provide two benefits. First, they provide a way to share code among several applications. If you have such code, you can create a library with it and link the library with any application that needs it. Second, libraries provide a way to reduce the complexity of very large applications. Such applications can build and maintain relatively independent portions as libraries and so reduce the burden on programmers working on other portions. Building a library simply means creating .o files (by compiling your code with the -c option) and combining the .o files into a library using the CC command. You can build two kinds of libraries, static (archive) libraries and dynamic (shared) libraries. With static (archive) libraries, objects within the library are linked into the program’s executable file at link time. Only those .o files from the library that are needed by the application are linked into the executable. The name of a static (archive) library generally ends with a .a suffix. With dynamic (shared) libraries, objects within the library are not linked into the program’s executable file, but rather the linker notes in the executable that the program depends on the library. When the program is executed, the system loads the dynamic libraries that the program requires. If two programs that use the same dynamic library execute at the same time, the operating system shares the library among the programs. The name of a dynamic (shared) library ends with a .so suffix. Linking dynamically with shared libraries has several advantages over linking statically with archive libraries:
However, dynamic libraries have some disadvantages:
16.2 Building Static (Archive) LibrariesThe mechanism for building static (archive) libraries is similar to that of building an executable. A collection of object (.o) files can be combined into a single library using the– xar option of CC. You should build static (archive) libraries using CC -xar instead of using the ar command directly. The C++ language generally requires that the compiler maintain more information than can be accommodated with traditional .o files, particularly template instances. The– xar option ensures that all necessary information, including template instances, is included in the library. You might not be able to accomplish this in a normal programming environment since make might not know which template files are actually created and referenced. Without CC -xar, referenced template instances might not be included in the library, as required. For example:
The– xar flag causes CC to create a static (archive) library. The– o directive is required to name the newly created library. The compiler examines the object files on the command line, cross-references the object files with those known to the template repository, and adds those templates required by the user’s object files (along with the main object files themselves) to the archive. Note – Use the -xar flag for creating or updating an existing archive only. Do not use it to maintain an archive. The -xar option is equivalent to ar -cr. It is a good idea to have only one function in each .o file. If you are linking with an archive, an entire .o file from the archive is linked into your application when a symbol is needed from that particular .o file. Having one function in each .o file ensures that only those symbols needed by the application will be linked from the archive. 16.3 Building Dynamic (Shared) LibrariesDynamic (shared) libraries are built the same way as static (archive) libraries, except that you use– G instead of– xar on the command line. You should not use ld directly. As with static libraries, the CC command ensures that all the necessary template instances from the template repository are included in the library if you are using templates. All static constructors in a dynamic library that is linked to an application are called before main() is executed and all static destructors are called after main() exits. If a shared library is opened using dlopen(), all static constructors are executed at dlopen() and all static destructors are executed at dlclose(). You should use CC -G to build a dynamic library. When you use ld (the link-editor) or cc (the C compiler) to build a dynamic library, exceptions might not work and the global variables that are defined in the library are not initialized. To build a dynamic (shared) library, you must create relocatable object files by compiling each object with the– Kpic or– KPIC option of CC. You can then build a dynamic library with these relocatable object files. If you get any bizarre link failures, you might have forgotten to compile some objects with– Kpic or– KPIC. To build a C++ dynamic library named libfoo.so that contains objects from source files lsrc1.cc and lsrc2.cc, type:
The -G option specifies the construction of a dynamic library. The -o option specifies the file name for the library. The -h option specifies a name for the shared library. The -Kpic option specifies that the object files are to be position-independent. Note – The CC -G command does not pass any -l options to ld. If you want the shared library to have a dependency on another shared library, you must pass the necessary -l option on the command line. For example, if you want the shared library to be dependent upon libCrun.so, you must pass -lCr un on the command line. 16.4 Building Shared Libraries That Contain ExceptionsNever use -Bsymbolic with programs containing C++ code, use linker map files instead. With -Bsymbolic, references in different modules can bind to different copies of what is supposed to be one global object. The exception mechanism relies on comparing addresses. If you have two copies of something, their addresses won’t compare equal, and the exception mechanism can fail because the exception mechanism relies on comparing what are supposed to be unique addresses. When shared libraries are opened using dlopen(), you must use RTLD_GLOBAL for exceptions to work. 16.5 Building Libraries for Private UseWhen an organization builds a library for internal use only, the library can be built with options that are not advised for more general use. In particular, the library need not comply with the system’s application binary interface (ABI). For example, the library can be compiled with the -fast option to improve its performance on a known architecture. Likewise, it can be compiled with the -xregs=float option to improve performance. 16.6 Building Libraries for Public UseWhen an organization builds a library for use by other organizations, the management of the libraries, platform generality, and other issues become significant. A simple test for whether or not a library is public is to ask if the application programmer can recompile the library easily. Public libraries should be built in conformance with the system’s application binary interface (ABI). In general, this means that any processor-specific options should be avoided. (For example, do not use– fast or– xtarget.) The SPARC ABI reserves some registers exclusively for applications. For V7 and V8, these registers are %g2, %g3, and %g4. For V9, these registers are %g2 and %g3. Since most compilations are for applications, the C++ compiler, by default, uses these registers for scratch registers, improving program performance. However, use of these registers in a public library is generally not compliant with the SPARC ABI. When building a library for public use, compile all objects with the -xregs=no%appl option to ensure that the application registers are not used. 16.7 Building a Library That Has a C APIIf you want to build a library that is written in C++ but that can be used with a C program, you must create a C API (application programming interface). To do this, make all the exported functions extern "C". Note that this can be done only for global functions and not for member functions. If a C-interface library needs C++ run-time support and you are linking with cc, then you must also link your application with either libC (compatibility mode) or libCrun (standard mode) when you use the C-interface library. (If the C-interface library does not need C++ run-time support, then you do not have to link with libC or libCrun.) The steps for linking differ for archived and shared libraries. When providing an archived C-interface library, you must provide instructions on how to use the library.
When providing a shared C-interface library you must create a dependency on libC or libCrun at the time that you build the library. When the shared library has the correct dependency, you do not need to add -lC or -lCrun to the command line when you use the library.
If you want to remove any dependency on the C++ runtime libraries, you should enforce the following coding rules in your library sources:
16.8 Using dlopen to Access a C++ Library From a C ProgramIf you want to use dlopen() to open a C++ shared library from a C program, make sure that the shared library has a dependency on the appropriate C++ runtime (libC.so.5 for -compat=4, or libCrun.so.1 for -compat=5). To do this, add -lC for -compat=4 or add -lCrun for -compat=5 to the command line when building the shared library. For example:
If the shared library uses exceptions and does not have a dependency on the C++ runtime library, your C program might behave erratically. Note – When shared libraries are opened with dlopen(), RTLD_GLOBAL must be used for exceptions to work. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||