News:

This week IPhone 15 Pro winner is karn
You can be too a winner! Become the top poster of the week and win valuable prizes.  More details are You are not allowed to view links. Register or Login 

Main Menu

c++ Tips: IO - notes on formatted streams io

Started by ben2ong2, October 06, 2006, 11:19:49 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

ben2ong2

(Source: Jamshid Afshar, You are not allowed to view links. Register or Login)


NG: C Ng (el934931@stoat.shef.ac.uk)

|>   I am a Pascal programmer and new to C++.

|>   I have certain queries about formatted I/O, I read several books on C++ but
|> apparently I don't seem to get a specific answer.

KANZE: You are not allowed to view links. Register or Login (J. Kanze), 22 Jun 95

This seems to be the single biggest problem with iostream; most books
just skip over it.  A shame, since it is incredibly flexible and
powerful.

NG:

|>   Suppose I want to write two column of variables a and b, both real to an
|> output file. If my data are 1.23e10, 21e19, 7.4, 127e3 etc. my output will
|> read 1.23e10, 2.1e20, 7.4, 127000. Now what I want is some kind of formatting
|> which I can do easily in Pascal, that is, I can specify that  I want all data
|> to be in decimal format with so many no. of decimal places, or exponential
|> format with so many decimal places for the pre-exponent and the exponent, and
|> any unfilled spaces will be padded with blanks.

KANZE:

You have several aspects of the format, which are controlled separately.

There are three basic output formats for floating point data: fixed,
scientic, and mixed.  (The default is mixed.)  You can choose by means
of the setf member function of your output stream:

    cout.setf( ios::fixed , ios::floatfield ) ;

The exact meaning of precision depends on the format.  For fixed, it is
the number of digits after the decimal point; for the other formats, it
is the total number of digits displayed.  The precision is set by:

    cout.precision( 3 ) ;

The width is the minimum number of characters output.  (There may be
more, if the combination of value and format require it.)  To set:

    cout.width( 7 ) ;

There are a couple of other odd flags, for example:

    ios::showpoint      always display the decimal point, even if
                        nothing follows.
    ios::uppercase      in scientific format, use E instead of e.

These can be set with the single parameter form of setf, and reset using
unsetf, e.g.:

    cout.setf( ios::showpoint ) ;
    cout.unsetf( ios::showpoint ) ;

The fill character can be set using:

    cout.fill( '0' ) ;

With the exception of width, these parameters are `sticky'; they retain
the last value set.  For this reason, it is generally considered polite
to save them before modification, and to restore them when you are
through.  The normal way of doing this is to use an iosave class:

    iosave          save( cout ) ;

This class will restore the values when it goes out of scope.

Regretfully, this class is not provided by the implementations, and at
present, there is no portable implementation possible.  An
implementation for SunCC 4.0.1 is appended.

All of these parameters can be set by means of `manipulators', as well.
In the case of width, this is the usual method, since it must be set for
each value output:

    cout << setw( 7 ) << d ;

Precision is also occasionally set this way (manipulator setprecision).
It is somewhat more difficult to set the format, since it is necessary
to first reset the preceding value:

    cout << resetiosflags( ios::floatfield ) << setiosflags( ios::fixed) << d ;

(I think that you will agree that if nothing else, the cout.setf format
is less verbose.)

Thus, if in a function, you want to output the classical fortran 6.2
format:

    iosave              save( cout ) ;
    cout.setf( ios::fixed , ios::floatfield ) ;
    cout.precision( 2 ) ;
    cout << setw( 6 ) << d ;

For those already familiar with iostreams, it isn't difficult to
encapsulate this into a fmt manipulator, which takes a string describing
the format, sets all of the necessary flags to implement it, after
saving the preceding configuration in a temporary variable, which
restores it when the temporary is destructed (at the end of the full
expression with a modern compiler).  This is not a job for a beginner
with iostreams (or C++), though.


iosave class:
------------------------------------------------------
class iosave
{
public :
                        iosave( ios& stream ) ;
                        ~iosave() ;
private :
                        iosave( iosave const& ) ;
    iosave&             operator=( iosave const& ) ;

    ios*                theStream ;
    long                theFlags ;
    char                theFill ;
    int                 thePrecision ;
} ;

iosave::iosave( ios& stream )
    :   theStream( &stream )
    ,   theFlags( stream.flags() )
    ,   theFill( stream.fill() )
    ,   thePrecision( stream.precision() )
{
}

iosave::~iosave()
{
    theStream->flags( theFlags ) ;
    theStream->fill( theFill ) ;
    theStream->precision( thePrecision ) ;
}
You are not allowed to view links. Register or Login
You are not allowed to view links. Register or Login