Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

C++ Manipulators and Stream Flags: It is missing manipulator for the case where basefield has to be 0

9 views
Skip to first unread message

Christiano

unread,
May 4, 2017, 10:23:37 PM5/4/17
to
------- Introduction ---------------

The book "Programming: Principles and Practice using C++" [1] says on chapter 11:

"Terms such as hex and oct that are used to change the behavior of the stream are called manipulators."

An example:

#include <iostream>
using namespace std;
int main()
{
cout << hex << 1234 << endl;

return 0;
}

Manipulators change stream flags whose format is represented by the type fmtflags.

Here, we have a list with fmtflags:

basefield
oct
hex
dec
adjustfield
left
right
internal
floatfield
scientific
fixed
---------
boolalpha
showbase
showpoint
showpos
skipws
unitbuf
uppercase

from http://en.cppreference.com/w/cpp/io/ios_base/fmtflags

A combination of flags determines how the stream behaves, moreover, such a combination can be more easily and correctly altered by manipulators.

You can see the relationship between the flags and the behavior by looking at the following tables (from C++11 specification [3] : § 22.4.2.1.2 and §
22.4.2.2.2).


1. Input

1.1 Integers
+------------------------+------------------+
| State | stdio equivalent |
+------------------------+------------------+
| basefield == oct | %o |
| basefield == hex | %X |
| basefield == 0 | %i | [2]
| signed integral type | %d |
| unsigned integral type | %u |
+------------------------+------------------+

1.2 Floating point

For conversions to a floating type the specifier is %g.

2. Output

2.1 Integers
+--------------------------------------------+------------------+
| State | stdio equivalent |
+--------------------------------------------+------------------+
| basefield == oct | %o |
| (basefield == ios_base::hex) && !uppercase | %x | [2]
| (basefield == ios_base::hex) | %X |
| for a signed integral type | %d |
| for an unsigned integral type | %u |
+--------------------------------------------+------------------++


2.2 Floating point

+----------------------------------------------------------------------+------------------+
| State | stdio equivalent |
+----------------------------------------------------------------------+------------------+
| floatfield == ios_base::fixed | %f |
| floatfield == ios_base::scientific && !uppercase | %e |
| floatfield == ios_base::scientific | %E | [2]
| floatfield == (ios_base::fixed | ios_base::scientific) && !uppercase | %a |
| floatfield == (ios_base::fixed | ios_base::scientific) | %A |
| !uppercase | %g |
| otherwise | %G |
+----------------------------------------------------------------------+------------------+

And you can see the relationship between the manipulators and the flags by looking at the following table (from C++11 specification [3] : § 27.5.6).

+--------------+------------------------------------------------------------------------------+
| Manipulator | Effect |
+--------------+------------------------------------------------------------------------------+
| boolalpha | Calls str.setf(ios_base::boolalpha) |
| noboolalpha | Calls str.unsetf(ios_base::boolalpha) |
| showbase | Calls str.setf(ios_base::showbase) |
| noshowbase | Calls str.unsetf(ios_base::showbase) |
| showpoint | Calls str.setf(ios_base::showpoint) |
| noshowpoint | Calls str.unsetf(ios_base::showpoint) |
| showpos | Calls str.setf(ios_base::showpos) |
| noshowpos | Calls str.unsetf(ios_base::showpos) |
| skipws | Calls str.setf(ios_base::skipws) |
| noskipws | Calls str.unsetf(ios_base::skipws) |
| uppercase | Calls str.setf(ios_base::uppercase) |
| nouppercase | Calls str.unsetf(ios_base::uppercase) |
| unitbuf | Calls str.setf(ios_base::unitbuf) |
| nounitbuf | Calls str.unsetf(ios_base::unitbuf) |
| internal | Calls str.setf(ios_base::internal, ios_base::adjustfield) |
| left | Calls str.setf(ios_base::left, ios_base::adjustfield) |
| right | Calls str.setf(ios_base::right, ios_base::adjustfield) |
| dec | Calls str.setf(ios_base::dec, ios_base::basefield) |
| hex | Calls str.setf(ios_base::hex, ios_base::basefield) |
| oct | Calls str.setf(ios_base::oct, ios_base::basefield) |
| fixed | Calls str.setf(ios_base::fixed, ios_base::floatfield) |
| scientific | Calls str.setf(ios_base::scientific, ios_base::floatfield) |
| hexfloat | Calls str.setf(ios_base::fixed | ios_base::scientific, ios_base::floatfield) |
| defaultfloat | Calls str.unsetf(ios_base::floatfield) |
+--------------+------------------------------------------------------------------------------+


------- The "Problem" ---------------

The book [1] on chapter 11 put a code similar to this:

#include<iostream>
#include<vector>
using namespace std;

int main()
{

cin.unsetf(ios_base::dec);
cin.unsetf(ios_base::oct);
cin.unsetf(ios_base::hex);

int x;

cin >> x;

cout << x;

return 0;
}

Or equivalent:

#include<iostream>
#include<vector>
using namespace std;

int main()
{
cin.unsetf(ios_base::basefield);

int x;

cin >> x;

cout << x << endl;

return 0;
}

Running this program:
$ CC a.cpp
$ ./a.out
10
10
$ ./a.out
0xa
10
$ ./a.out
012
10
$

The book says "You can get >> to accept and correctly interpret the 0 and 0x prefixes. To do that, you 'unset' all the defaults.".
And if you see the first table, then you can see that the "stdio equivalent" is %i, exactly as expected because this:
http://stackoverflow.com/questions/1893490/difference-between-format-specifiers-i-and-d-in-printf

The "problem" is:

All the "stdio equivalent" can be reached using manipulators, with one exception: %i,
which requires the programmer to write manually the flags

Would not it be more appropriate, from the point of view of orthogonality, that there was a manipulator to cover that particular case? (That is, the
case where basefield has to be 0).

-------------------------------------------------------------------------
[1] http://www.stroustrup.com/programming.html / ISBN 978-0321-992789
[2] All tables are ordered. That is, the first line whose condition is true applies.
[3] ISO/IEC 14882:2011[E] Information technology — Programming languages — C++
Tables were generated by https://ozh.github.io/ascii-tables/
I have the original books/standard. I quote some fair minimal excerpts for research purpose.

Alf P. Steinbach

unread,
May 4, 2017, 11:03:41 PM5/4/17
to
On 05-May-17 4:23 AM, Christiano wrote:
> All the "stdio equivalent" can be reached using manipulators, with one
> exception: %i,
> which requires the programmer to write manually the flags
>
> Would not it be more appropriate, from the point of view of
> orthogonality, that there was a manipulator to cover that particular
> case? (That is, the case where basefield has to be 0).

Yes, I agree.

And not having it is inconsistent with having `std::defaultfloat`.

But of all the problems with iostreams, this must IMO count as one of
the least significant:

(1) it's just a lack of convenience, for as you have shown you can
easily clear the default decimal format (see C++14 §27.5.5.2/3 for the
defaults), and

(2) it's one to three lines of code to define the desired manipulator,
depending on how you format it, if you really want such manipulator.

I remember that in C++03 hex input was a problem, because overflow gave
formally UB for fscanf (I think it was) which was used to define the
effect of the >> operator. I proved to my own satisfaction that one
could make Visual C++ behave in an ungood way. That was fixed in C++11.

A nice approach is to read all user input via `getline`, and parse that.


Cheers!,

- Alf

0 new messages