DIGITAL C++
Using DIGITAL C++ for DIGITAL UNIX Systems
7.4.4 Upgrading from the DIGITAL C++ Class Library Complex to the ANSI Complex Class
This section explains how to upgrade from the pre-ANSI DIGITAL C++
complex library to the current DIGITAL C++ standard complex library.
In the ANSI library, complex objects are templatized on the type of the
real and imaginary parts, the pre-ANSI DIGITAL C++ library, complex
objects are not templatized. The pre-ANSI library assumes the type is
double, whereas the new library provides specializations for float,
double, and long double as well as allowing users to specialize on
their own floating point types.
Also note that mathematical error checking is not supported in the ANSI
library. Users who rely on detection of underflow, overflow, and divide
by zero should continue using the pre-ANSI DIGITAL C++ complex
library.
The following is a detailed list of important changes:
- Change #include <complex.h> or
#include <complex.hxx> to #include <complex>.
- Change all declarations of complex to
complex<double>, for example:
to:
- The polar() function no longer
supplies a default value of 0 for the second argument. Users will have
to explicitly add it to any calls that have only one argument, for
example:
complex c;
c = polar(c); // get polar
|
to:
complex<double> c;
c = polar(c,0.0);
|
- If you are calling a mathematical function or mathematical operator
that takes scalars as arguments (polar()
for example), then you must adjust the arguments you pass in to be the
same type as the complex template parameter type. For example, you
would have to change:
complex c = polar(0,0);
complex c2 = c+1;
|
to:
complex<double> c = polar(0.0,0.0); // 0.0 is double
complex<double> c2= c + 1.0; // 1.0 is double
|
- The complex_zero variable is not declared in the complex
header file. If you want to use it, you will have to declare it
yourself. For example, add the following to the top of your source file:
static const complex<double> complex_zero(0.0,0.0);
|
- The sqr() and arg1() functions are gone. If you want to
continue to use them, you should define them in one of your own
headers, using the following definitions:
template <class T>
inline complex<T> sqr(const complex<T>& a)
{
return complex<T>(real(a) * real(a) - imag(a) * imag(a),
2 * real(a) * imag(a));
}
template <class T>
inline T arg1(const complex<T>& a)
{
double val = arg(a);
if(val > -M_PI && val <= M_PI)
return val;
if(val > M_PI)
return val - (2*M_PI);
// val <= -PI
return val + (2*M_PI);
}
|
- The pow(complex, int) function is no
longer provided. You must use pow(complex<double>, double). This means
changing calls such as:
to:
This might yield different results. If the function previously was
underflowing or overflowing, it might not continue to happen.
- The complex output operator (<<) does not insert a space
between the comma and the imaginary part. If you want the space, you
would need to print the real and imaginary parts separately, adding
your own comma and space; that is:
complex<double> c;
cout << "(" << c.real() << ", " << c.imag() << ")"; // add extra space
|
- The complex input operator (>>) does not raise an Objection
if bad input is detected; it instead sets input stream's state to ios::failbit.
- Floating point overflow, underflow, and divide by zero do not set
errno and will cause undefined behavior.
DIGITAL plans to do complex error checking and error notification in a
subsequent release.
- You should no longer need to explicitly link your program with the
complex library. It is automatically linked in as part of the Standard
Library. However, you must still explicitly link in the C math library,
as shown in the following example:
#include <complex>
int main() {
complex<double> c1(1,1), c2(3.14,3.14);
cout << "c2/c1: " << c2/c1 << endl;
}
|
7.4.5 Upgrading from the DIGITAL C++ IOStreams library to the DIGITAL C++ Standard Library
This section explains how to upgrade from the pre-ANSI DIGITAL C++
IOStreams library to the ANSI DIGITAL C++ IOStreams library. In this
section, pre-ANSI IOStreams refers to versions of the IOStreams library
found in the DIGITAL C++ Class Library; ANSI IOStreams refers to
versions found in the DIGITAL C++ Standard Library.
There are a number of differences between the pre-ANSI and ANSI
IOstream library. One major difference between the pre-ANSI and ANSI
IOstream library is that the ANSI library is templatized on the object
input/output on which operations are being performed. In the pre-ANSI
library, IOStreams has no templates. The ANSI library also provides
specializations for char and wchar_t.
Important differences are as follows:
- With the current compiler, you access the pre-ANSI IOstream library
by default in non strict_ansi compiler
modes. You can control the version of IOStreams you use with the __USE_STD_IOSTREAM and __NO_USE_STD_IOSTREAM macros. If you want to
use the ANSI IOstream library, do either of the following:
- -D__USE_STD_IOSTREAM on the command
line.
- #define __USE_STD_IOSTREAM in your
source file before any include files.
- Header names are different in the ANSI library, so to use ANSI
IOStreams, change the IOStreams headers you include as follows:
From |
To |
#include <iostream.h>
#include <iostream.hxx>
|
#include <iostream>
|
#include <fstream.h>
#include <fstream.hxx>
|
#include <fstream>
|
#include <strstream.h>
#include <strstream.hxx>
|
#include <strstream>
|
#include <iomanip.h>
#include <iomanip.hxx>
|
#include <iomanip>
|
- All Standard Library names in the ANSI IOStreams library are in
namespace std. Typically you would
qualify each Standard Library name with std:: or put using namespace
std; at the top of your source file. To facilitate
upgrading in all but strict_ansi and
strict_ansi_errors mode, using namespace std; is set by default. In
strict_ansi or strict_ansi_errors modes, after including an
ANSI IOStream header, you must qualify each name inside namespace std individually or do
- In the pre-ANSI IOstream library, including <iomanip.h> or <strstream.h> gave you access to cout, cin, and
cerr. To access the predefined streams
with the ANSI IOStreams library, make the following changes:
change
#include <iomanip.h>
to
#include <iomanip>
#include <iostream>
#include
using namespace std;
|
change
#include <strstream.h>
to
#include <strstream>
#include <iostream>
#include
using namespace std;
|
- The istream::ipfx, istream::isfx, ostream::opfx, ostream::osfx do not exist in the ANSI
IOStreams. Their functionality is provided by the sentry class found in
basic_istream and basic_ostream, respectively. Common prefix code
is provided by the sentry's constructor. Common suffix code is provided
by the sentry's destructor. So calls to ipfx(), isfx(),
opfx(), and osfx() have their functionality replaced by
construction and destruction of std::istream::sentry
objects and std::ostream::sentry
object respectively. For example:
#include <iostream.hxx> | #include <iostream.hxx>
void func (istream &is) | void func (ostream &os)
{ | {
if (is.ipfx()) | if (os.opfx())
... | ...
is.isfx(); | os.osfx();
} | }
|
Would be coded as: | Would be coded as:
|
#include <iostream> | #include <iostream>
void func (istream &is) | void func (ostream &os)
{ | {
istream::sentry ipfx(is); | ostream::sentry opfx(os);
if (ipfx) | if (opfx)
... | ...
//is.isfx(); implicit in dtor | //os.osfx(); implicit in dtor
} | }
|
- The following macros from the pre-ANSI <iomanip.h> are no longer available in
<iomanip>:
SMANIP, IMANIP, OMANIP, IOMANIP,
SAPP, IAPP, OAPP, IOAPP,
SMANIPREF, IMANIPREF, OMANIPREF, IOMANIPREF,
SAPPREF, IAPPREF, OAPPREF, IOAPPREF
|
You can add them yourself, but their use will not be portable.
- The streambuf::stossc() function,
which advances the get pointer forward by one character in a stream
buffer, is not available in the ANSI IOstream library. You can make use
of the std::streambuf::sbumpc() function
to move the get pointer forward one place. This function returns the
character it moved past. These two functions are not exactly
equivalent---if the get pointer is already beyond the end, stossc() does nothing, and sbumpc() returns EOF.
istream &extract(istream &is)
{
...
is.rdbuf()->stossc();
}
|
- ios::bitalloc() is no longer
available in the ANSI IOstream library.
- The filebuf constructors have changed
in the ANSI IOstream library. The pre-ANSI filebuf class contained three constructors:
class filebuf : public streambuf
{
filebuf();
filebuf(int fd);
filebuf(int fd, char * p, int len);
...
}
|
In the ANSI IOstream library, filebuf
is a typedef for basic_filebuf<char>, and the C++ Working
Paper defines one filebuf constructor:
To facilitate backward compatibility, the DIGITAL C++ ANSI
IOStream library does provide basic_filebuf(int
fd) as an extension. However, the use of extensions is not
portable.
For example, consider the filebuf constructors in the following pre-ANSI
IOStream library program:
#include <fstream.hxx>
int main () {
int fd = 1;
const int BUFLEN = 1024;
char buf [BUFLEN];
filebuf fb(fd,buf,BUFLEN);
filebuf fb1(fd);
return 0;
}
|
To be strictly ANSI conforming, you would need to recode as follows:
filebuf fb(fd,buf,BUFLEN); as filebuf fb(); and
filebuf fb1(fd); as filebuf fb1();
|
If you want to make use of the DIGITAL C++ ANSI IOStream filebuf(fd) extension, you could recode:
filebuf fb(fd,buf,BUFLEN); as filebuf fb(fd); and
filebuf fb1(fd); as filebuf fb1(fd);
|
- The DIGITAL C++ ANSI IOstream library contains support for the
filebuf::fd() function, which returns the
file descriptor for the filebuf object
and EOF if the filebuf object is closed
as a nonportable extension. Note that this function is not supported
under the -std strict_ansi or -std strict_ansi_errors compiler modes.
- The following functions are not defined in the ANSI IOStreams
library. They are provided in the DIGITAL C++ ANSI IOstream library
for backward compatibility only. Their use is not portable.
ifstream::ifstream(int fd);
ifstream::ifstream(int fd, char *p, int len)
ofstream::ofstream(int fd);
ofstream::ofstream(int fd, char *p, int len);
fstream::fstream(int fd);
fstream::fstream(int fd, char *p, int len);
|
- The following attach functions, which
attach, respectively, a filebuf, fstream, ofstream, and ifstream to a file are not available in the
ANSI IOstream library:
filebuf::attach(int);
fstream::attach(int);
ifstream::attach(int);
ofstream::attach(int);
|
If you do not want to make use of DIGITAL C++ ANSI IOstream
library extensions, you must recode the use of attach as follows:
From:
#include <fstream.hxx>
#include <stdio.h>
#include <fcntl.h>
int main () {
int fd;
fd = open("t27.in",O_RDWR | O_CREAT, 0644);
ifstream ifs;
ifs.attach(fd);
fd = creat("t28.out",0644);
ofstream of;
of.attach(fd);
return 0;
}
|
To:
#include <fstream>
int main () {
ifstream ifs("t27.in", ios::in | ios::out);
ofstream ofs("t28.out");
return 0;
}
|
- The ios enumerators for controlling the opening of files, ios::nocreate and ios::noreplace, are not available in the ANSI
IOstream library.
- The istream_withassign and ostream_withassign classes are not available in
the ANSI IOstream library.
- In the ANSI IOstream library ios_base::width() applies to all formatted
inserters including operator << (char). This means that the stream
width specified by either the manipulator
setw() or the ios_base::width() member function will apply
padding to the next output item even if it is a char. This was not the
case in the pre-ANSI IOStreams library, where width() applied to all formatted inserters
except the char inserter. The
reasons for the change (to allow ostream::operator<<(char) to do
formatting) are:
- It allows operator<< functions
to do formatting consistently.
- It allows operator<<(char) and
put(char) (formatted and unformatted
operations on char) to have different
functionality.
Consider the following example:
#ifdef __USE_STD_IOSTREAM
# include <iostream>
# include <iomanip>
#else
# include <iostream.hxx>
# include <iomanip.hxx>
#endif
int main () {
cout.width(10);
cout.fill('^');
cout << 'x' << '\n';
cout << '[' << setw(10) << 'x' << ']' << endl;
return 0;
}
|
In the ANSI IOstream library the output is:
In the pre-ANSI IOstream library the output is:
- In the pre-ANSI IOstream library, printing signed
char* or a unsigned char*
printed the address of the string. In the ANSI IOstream library the
string is printed. Consider the following example:
#ifdef __USE_STD_IOSTREAM
#include <iostream>
#else
#include <iostream.hxx>
#endif
int main () {
char * cs = (char *) "Hello";
signed char *ss = (signed char *) "world";
unsigned char *us = (unsigned char *) "again";
cout << cs << " " << ss << " " << us << endl;
return 0;
}
|
The output in the ANSI IOstream library is:
The output in the pre-ANSI IOstream library is:
Hello 0x120001748 0x120001740
|
To obtain output equivalent to the pre-ANSI IOStreams, you might do
the following:
cout << hex << showbase << (long) ss << " " << (long) us << endl;
|
- In the pre-ANSI IOstream library printing a signed char prints its integer value. In the
ANSI IOstream library printing a signed
char prints it as a character. Consider the following
example:
#ifdef __USE_STD_IOSTREAM
#include <iostream>
#else
#include <iostream.hxx>
#endif
int main () {
signed char c = (signed char) 'c';
cout << c << endl;
return 0;
}
|
The output in the ANSI IOstream library is:
The output in the pre-ANSI IOstream library is:
To obtain output equivalent to the pre-ANSI IOStreams, you must do
the following:
cout << (long) c << endl;
|
- In the ANSI IOstream library, reading invalid floating point input
(where invalid input is caused by no digits following the letter e or E
and an optional sign) from a stream sets failbit to flag this error
state. In the pre-ANSI IOstream library, these type of error conditions
might not be detected. Consider this program fragment:
double i;
cin >> i;
cout << cin.rdstate() << ' ' << i << endl;
|
On the input: 123123e
The output in the ANSI IOstream library
is:
4 2.65261e-314 // failbit set
|
The output in the pre-ANSI IOstream library is:
- In the ANSI IOstream library, reading integer input (which is
truncated as the result of a conversion operation) from a stream sets
failbit to flag this overflow condition. In the pre-ANSI IOStream
library, these types of conditions might not be detected. Consider this
program fragment:
int i;
cin >> i;
cout << cin.rdstate() << ' ' << i << endl;
|
On the input: 9999999999999999
The output in the ANSI IOstream
library is:
4 1874919423 // failbit set
|
The output in the pre-ANSI IOstream library is:
0 1874919423 // goodbit set
|
In the ANSI IOstream library, reading -0 from a stream into an
unsigned int outputs 0; this was not the
case with the pre-ANSI IOstream library. Consider the following:
unsigned int ui;
cin >> ui;
cout << cin.rdstate() << ' ' << ui << endl;
|
On the input: -0
The output in the ANSI IOstream library is:
- In the ANSI IOstream library, the istream::getline() function extracts characters
and stores them into successive locations of an array whose first
element is designated by s. If n-1 characters are stored, failbit is
set. This was not the case in the pre-ANSI IOstream library. Consider
the following:
main()
{
char buffer[10];
cin.getline (buffer,10);
cout << cin.rdstate() << ' ' << buffer << endl;
return 0;
}
|
With input of: 1234567890
The output in the ANSI IOstream
library is:
The output in the pre-ANSI IOstream library is:
- When printing addresses, the ANSI library does not print a leading
"0x" to indicate a hexadecimal base. The pre-ANSI library
did. Consider the following:
#include <iostream>
main()
{
double d;
int i;
void *p = (void *) &d;
int *pi = &i;
cout << (void *) 0 << ' ' << p << ' ' pi << endl;
}
|
The output in the ANSI IOstream library is:
The output in the pre-ANSI IOstream library is:
0x0 0x11fffdc40 0x11fffdc38
|
- basic_filebuf::setbuf is a protected
member function in the ANSI IOstream library. Therefore, the following
will no longer compile:
int main() {
filebuf fb;
...
fb.setbuf(0,0);
return 0;
}
|