C++ streams and Formatting manipulators
C++ provides a way to format the stream data such as intending the data of output stream, setting the base as hexadecimal or octal, etc. C++ provides this functionality through ios
and ios_base
classes.
The ios_base
and ios
classes provides the formatting functionality by implementing some format states information and bit masks. The ios_base
class contains the members which can be used to change the precision, width, and formatting control flags of the stream.
class ios_base
{
public:
...
typedef _Ios_Fmtflags fmtflags;
...
protected:
...
streamsize _M_precision;
streamsize _M_width;
fmtflags _M_flags;
...
};
The ios
class contains the fill attribute which can be used with width attribute to add some characters before or after the output.
template<typename _CharT, typename _Traits>
class basic_ios : public ios_base
{
...
protected:
...
mutable char_type _M_fill;
}
Setting precision
ios_base
class provides precision
function to set the precision of floating point output. There are two variants of this function:
streamsize precision(streamsize __prec)
receives the new precision value to be set and returns the old precison value.inline streamsize
precision(streamsize __prec)
{
streamsize __old = _M_precision;
_M_precision = __prec;
return __old;
}
- The following example changes the precision value of floating point value
#include <iostream>
using namespace std;
int main()
{
float numerator = 1, denominator = 3;
cout<<(numerator/denominator)<<"\n";
cout.precision(4);
cout<<(numerator/denominator)<<"\n";
return 0;
}
$ g++ format.cc -o format
$ ./format
0.333333
0.3333
streamsize precision const()
returns the exsiting value of precision.inline streamsize
precision(streamsize __prec)
{
streamsize __old = _M_precision;
_M_precision = __prec;
return __old;
}
Setting width and fill characters
The ios_base
class provides the width
function which can be used to specify the minimum number of characters to be used for the next output operation of an integer.
inline streamsize width(streamsize __wide)
{
streamsize __old = _M_width;
_M_width = __wide;
return __old;
}
Consider the following example
#include <iostream>
using namespace std;
int main()
{
int distance = 10;
cout<<"The distance is ";
cout.width(5);
cout<<distance;
cout<<" metres\n";
return 0;
}
$ g++ format.cc -o format
$ ./format
The distance is 10 metres
In the above function we set the width for the output operation to 5. The value of distance
variable took only two characters, so three spcaes were printed to make sure the value of distance
variable was printed with 5 characters.
In the above example we spaces were used as padding characters to make sure the output of the distance
variable took 5 characters. We can change the padding character usng the fill
function provided in ios
class.
#include<iostream>
using namespace std;
int main()
{
int distance = 10;
cout<<"The distance is ";
cout.width(5);
cout.fill('#');
cout<<distance;
cout<<" metres\n";
return 0;
}
$ g++ format.cc -o format
$ ./format
The distance is ###10 metres
There are couple of points to keep in mind while using width
function.
width
function only affects the next output operation only. The subsequent output operations wouldn't use the specified width value.- If the value of the integer is greater than the value specified in
width
function, even then complete value of the integer would be printed.#include <iostream>
using namespace std;
int main()
{
int distance = 100;
cout<<"The distance is ";
cout.width(2);
cout<<distance;
cout<<" metres\n";
return 0;
}
$ g++ format.cc -o format
$ ./format
The distance is 100 metres
Both ios
and ios_base
class provide variants of functions fill
and width
which do not accpet any argument and return the exsiting values of fill character and width respectively.
char_type fill()
returns the corrent value of fill charactertemplate<typename _CharT, typename _Traits>
class basic_ios : public ios_base
{
...
public:
char_type
fill() const
{
if (!_M_fill_init)
{
_M_fill = this->widen(' ');
_M_fill_init = true;
}
return _M_fill;
}
}
streamsize width()
returns the current value of widthclass ios_base
{
...
public:
inline streamsize width() const
{ return _M_width; }
}
Manipulating formatting flags
The fmtflags
is interpreted as a bit mask whose various bits represent particluar features of formatting state.
enum _Ios_Fmtflags
{
_S_boolalpha = 1L << 0,
_S_dec = 1L << 1,
_S_fixed = 1L << 2,
_S_hex = 1L << 3,
_S_internal = 1L << 4,
_S_left = 1L << 5,
_S_oct = 1L << 6,
_S_right = 1L << 7,
_S_scientific = 1L << 8,
_S_showbase = 1L << 9,
_S_showpoint = 1L << 10,
_S_showpos = 1L << 11,
_S_skipws = 1L << 12,
_S_unitbuf = 1L << 13,
_S_uppercase = 1L << 14,
_S_adjustfield = _S_left | _S_right | _S_internal,
_S_basefield = _S_dec | _S_oct | _S_hex,
_S_floatfield = _S_scientific | _S_fixed,
_S_ios_fmtflags_end = 1L << 16
};
The ios_base class also defines some conatsnats that can be used to address the bits of the fmtflags
bitmask.
class ios_base
{
...
/// Insert/extract @c bool in alphabetic rather than numeric format.
static const fmtflags boolalpha = _S_boolalpha;
/// Converts integer input or generates integer output in decimal base.
static const fmtflags dec = _S_dec;
/// Generate floating-point output in fixed-point notation.
static const fmtflags fixed = _S_fixed;
/// Converts integer input or generates integer output in hexadecimal base.
static const fmtflags hex = _S_hex;
/// Adds fill characters at a designated internal point in certain
/// generated output, or identical to @c right if no such point is
/// designated.
static const fmtflags internal = _S_internal;
/// Adds fill characters on the right (final positions) of certain
/// generated output. (I.e., the thing you print is flush left.)
static const fmtflags left = _S_left;
/// Converts integer input or generates integer output in octal base.
static const fmtflags oct = _S_oct;
/// Adds fill characters on the left (initial positions) of certain
/// generated output. (I.e., the thing you print is flush right.)
static const fmtflags right = _S_right;
/// Generates floating-point output in scientific notation.
static const fmtflags scientific = _S_scientific;
/// Generates a prefix indicating the numeric base of generated integer
/// output.
static const fmtflags showbase = _S_showbase;
/// Generates a decimal-point character unconditionally in generated
/// floating-point output.
static const fmtflags showpoint = _S_showpoint;
/// Generates a + sign in non-negative generated numeric output.
static const fmtflags showpos = _S_showpos;
/// Skips leading white space before certain input operations.
static const fmtflags skipws = _S_skipws;
/// Flushes output after each output operation.
static const fmtflags unitbuf = _S_unitbuf;
/// Replaces certain lowercase letters with their uppercase equivalents
/// in generated output.
static const fmtflags uppercase = _S_uppercase;
/// A mask of left|right|internal. Useful for the 2-arg form of @c setf.
static const fmtflags adjustfield = _S_adjustfield;
/// A mask of dec|oct|hex. Useful for the 2-arg form of @c setf.
static const fmtflags basefield = _S_basefield;
/// A mask of scientific|fixed. Useful for the 2-arg form of @c setf.
static const fmtflags floatfield = _S_floatfield;
...
};
The istream and ostream classes inherit from ios_base and thus provide the functionality the formatting functionality for standard input (cin
), standard ouput (cout
), and standard error streams (cerr
.)
We can use the format flag to display the boolean variables as true
or false
instead of their numerical values.
#include <iostream>
using namespace std;
int main()
{
bool flag = true;
cout<<flag<<"\n";
cout.setf(ios::boolalpha);
cout<<flag<<"\n";
return 0;
}
$ g++ format.cc -o format
$ ./format
1
true
The ios_base
class provides couple of functions to manipulate the formatting flags.
setf
andflags
function to set the bits in the format flagsunsetf
function to clear the bits in the format flagsflags
function to retrieve the current format flags
setf function
The setf
function can be used to set the formatting flags maintained in ios_base class. There are two variants of setf
functions defined:
setf(fmtflags __fmtfl)
: This function sets the bits specified in__fmtfl
argument to the exisiting format flags. The bits on the exisiting format flags remain set and returns the older value o formatting control flags.- e.g. if the exisiting format field was set to a value
0x0040
and value0x0001
was passed as the argument then the new value of format flags would be0x4001
./**
* @brief Setting new format flags.
* @param fmtfl Additional flags to set.
* @return The previous format control flags.
*
* This function sets additional flags in format control. Flags that
* were previously set remain set.
*/
inline fmtflags
setf(fmtflags __fmtfl)
{
fmtflags __old = _M_flags;
_M_flags |= __fmtfl;
return __old;
}
- The following example sets the
ios::showpos
flag to display the+
sign for positive numbers. #include <iostream>
using namespace std;
int main()
{
int value = 10;
cout<<value<<"\n";
cout.setf(ios_base::showpos);
cout<<value<<"\n";
return 0;
}
$ g++ format.cc -o format
$ ./format
10
+10
setf(fmtflags __fmtfl, fmtflags __mask)
: This funtion clears the bits specified in__mask
argument from the exisiting format flag, and then set the bits speciified in the__fmtfl
argument to the exsiitng format flags and returns the older value o formatting control flags.- e.g. if the existing format flag had value
0x4001
and the setf was called with0x0002
as__fmtfl
and0x0001
as__mask
, then the new value of the format flag would be set to0x0042
./**
* @brief Setting new format flags.
* @param fmtfl Additional flags to set.
* @param mask The flags mask for @a fmtfl.
* @return The previous format control flags.
*
* This function clears @a mask in the format flags, then sets
* @a fmtfl @c & @a mask. An example mask is @c ios_base::adjustfield.
*/
inline fmtflags
setf(fmtflags __fmtfl, fmtflags __mask)
{
fmtflags __old = _M_flags;
_M_flags &= ~__mask;
_M_flags |= (__fmtfl & __mask);
return __old;
}
- The reason for providing this second variant is that some of the formatting features take more than one bits and only one of the bits should be enabled at once e.g. in order to set the justification of the output one of the three bits can be set (for left, right, or internal justifications.) If the justification is already set to something, then we need to clear the three bits first and then set the bit representing the new justification. For this purpose we can call the second variant which will clear the all the bits related to justification and then set the new justification bit. In order to do that the ios_base class defines some flags which represent the all the bits for specific features:
ios_base::basefield
ios_base::floatfield
ios_base::adjustfield
- The following example sets the base of the number to hexadecimal.
#include <iostream>
using namespace std;
int main()
{
int value = 10;
cout<<value<<"\n";
cout.setf(ios_base::hex, ios_base::basefield);
cout<<value<<"\n";
return 0;
}
$ g++ format.cc -o format
$ ./format
10
a
unsetf function
unsetf
function clears the bits specified as arguments.
inline void unsetf(fmtflags __mask) { _M_flags &= ~__mask; }
The following example sets the output format of floating point values to scientific and then unsets the formatting flag to set the default value.
#include <iostream>
using namespace std;
int main()
{
float value = 0.01f;
cout<<value<<"\n";
cout.setf(ios_base::scientific, ios_base::floatfield);
cout<<value<<"\n";
cout.unsetf(ios_base::scientific);
cout<<value<<"\n";
return 0;
}
$ g++ format.cc -o format
$ ./format
0.01
1.000000e-02
0.01
flags function
There are two variants of flags functions defined.
fmtflags flags(fmtflags __fmtfl)
overwrites the exisiting formatting flags to the value specified as argument and returns the old formatting flags.inline fmtflags flags(fmtflags __fmtfl)
{
fmtflags __old = _M_flags;
_M_flags = __fmtfl;
return __old;
}
- The following example sets the base for numbers to hexadecimal and sets the display of hexadecimal numbers to uppercase.
#include <iostream>
using namespace std;
int main()
{
int value = 10;
cout<<value<<"\n";
cout.flags(ios_base::hex | ios_base::uppercase);
cout<<value<<"\n";
return 0;
}
$ g++ format.cc -o format
$ ./format
10
A
fmtflags flags()
function returns the current value of formatting control flags.inline fmtflags flags() const { return _M_flags; }
Manipulators
C++ provides an elegant way to specify the formatting flags. ios_base
class defines some functions that call the the setf
and unsetf
functions with the appropriate flags. e.g. the boolalpha
function can be called, which will internally call the setf
function with the ios_base::boolaplha
argument.
#include <iostream>
using namespace std;
int main()
{
bool status = true;
cout<<status<<"\n";
boolalpha(cout);
cout<<status<<"\n";
return 0;
}
$ g++ format.cc -o format
$ ./format
1
true
However, things can be simplified further. The manipulators can be used with the insertion and extraction operators as well. e.g.
#include <iostream>
using namespace std;
int main()
{
bool status = true;
cout<<boolalpha<<status<<"\n";
return 0;
}
Following manipulators are defined in ios_base
class which call setf
and unsetf
functions internally.
Then there are some manipulators which do not call the setf
or unsetf
flags but manipulate the stream directly.
Manipulators with arguments
C++ also defines the manipulators which accept arguments as well.
Manipulator
setprecision
width
Argument
Precision value
Width value
As with other manipulators, these can be used alonf with insertion and extraction operators as well.
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
float numerator = 1, denominator = 3;
cout<<(numerator/denominator)<<"\n";
cout<<setprecision(4)<<(numerator/denominator)<<"\n";
return 0;
}
$ g++ format.cc -o format
$ ./format
0.333333
0.3333
Implementation of manipulators
All of the manipulators are defined as functions e.g. the manipulator boolalpha
is defined as:
inline ios_base& boolalpha(ios_base& __base)
{
__base.setf(ios_base::boolalpha);
return __base;
}
So a statement, cout << boolalpha
, is interpreted as cout.operator<<(boolaplha)
. Since boolapha
is defined as an function, so the insertion operator in cout<
is overloaded to recieve a function pointer as well.
template<typename _CharT, typename _Traits>
class basic_ostream : virtual public basic_ios<_CharT, _Traits>
{
public:
...
__ostream_type& operator<<(__ostream_type& (*__pf)(__ostream_type&))
{
__pf(*this);
return *this;
}
__ostream_type& operator<<(__ios_type& (*__pf)(__ios_type&))
{
__pf(*this);
return *this;
}
__ostream_type& operator<<(ios_base& (*__pf) (ios_base&))
{
__pf(*this);
return *this;
}
...
}
The overloaded operator function simply calls the function pointer with the cout
instance as the argument. Therefore, cout.operator<<(boolalpha)
ends up in calling boolalpha(cout)
.
However, things are a little bit different for the manipulators which receive arguments e.g. precision
which is defined as
inline streamsize
precision(streamsize __prec)
{
streamsize __old = _M_precision;
_M_precision = __prec;
return __old;
}
Therefore, for manipulators with agruments, not only the instance of cout
needs to be passed but also the precision value. Also, the precision
function does not return the instance of ostream
class, therefore it cannot be directly called, therefore the new function setprecision
is defined which can be used along with insertion operator.
inline _Setprecision setprecision(int __n)
{
_Setprecision __x;
__x._M_n = __n;
return __x;
}
The function setprecision
creates a instance of another class which stores the precision value. This instance is passed to the overloaded insertion operator as the argument which cals the precision
function with the precision value. Therefore, the statement cout << setprecision(4)
gets evaluated like this.
cout << setprecision(4)
statement is encountered and functionsetprecision(4)
is called.- Function
setprecision
creates an instance of_Setprecision
class and stores the value 4 in that instance. This instance of_Setprecision
class is then returned.inline _Setprecision setprecision(int __n)
{
_Setprecision __x;
__x._M_n = __n;
return __x;
}
- The function
cout.operator<<(setprecision(4))
gets evaluated asoperator<<(cout, instance of _Setprecision)
and the following global function for the overloaded insertion operator gets calledtemplate<typename _CharT, typename _Traits>
inline basic_ostream<_CharT,_Traits>&
operator<<(basic_ostream<_CharT,_Traits>& __os, _Setprecision __f)
{
__os.precision(__f._M_n);
return __os;
}
- The overloaded operator function, calls the
precision
function from thecout
, by passing the precsion stored in the instance of_Setprecision
instance.
Formatting with input streams
Most of the examples shown above were related to output stream. The formatting control flags and manipulators can also we used with input stream or cin
as well.
The formatted cin
input functions skip over the whitespaces in the beginning of the input stream. This behaviour can be changed using the ios_base::skipws
flag.
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
char name[20];
cout<<"Enter name ";
cin.unsetf(ios_base::skipws);
cin.getline(name,20);
cout<<"You entered "<<name<<"\n";
return 0;
}
$ g++ format.cc -o format
$ ./format
Enter name John
You entered John
The insertion operator >>
does not have the concept of destination boundaries. This can lead to overflow in the destination. e.g. if the variable <name
is defined as name[5]
, then it is possible to enter 10 characters with the statement cin>>name
. This will result in memory corruption. Using the width
manipulator we can tell the input stream to transfer only specified amount of bytes to the destination.
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
char name[5];
cin.width(5);
cin>>name;
cout<<"You entered "<<name<<'\n';
return 0;
}
$ g++ format.cc -o format
$ ./format
Smithers
You entered Smit
We can also set the ios_base::boolalpha
flag to indicate taht boolean flag input should be taken as true
and false
instead of 0 and 1.
#include <iostream>
using namespace std;
int main()
{
bool flag = true;
cin.setf(ios_base::boolalpha);
cin>>flag;
if (!cin.good())
cout<<"You entered a bad value\n";
else
cout<<"You entered "<<flag<<"\n";
return 0;
}
$ g++ format.cc -o format
$ ./format
true
You entered 1
$ ./format
false
You entered 0
$ ./format
yes
You entered a bad value
$ ./format
1
You entered a bad value
Formatted functions
One point to be noted is that the formatting functions, flags, and manipulators only affect the behavior of formatted functions only. For instance the ios_base::skipws
flag would only affect the formatted functions like cin>>
, cin.getline
only. The unformatted functions like cin.get
would not be impacted by these flags.