11

When using scanf() and its variants, the format specifier %i will accept data as hex (prefixed "0x"), octal (prefixed "0"), or decimal (no prefix), so for example the strings "0x10", "020", and "16" are all converted to an integer with decimal value 16.

Can this be done with std::istream::operator>> formatted input?

Using plain >> i with no i/o manipulator "0x10" is converted to zero (or rather the leading 0 is, the "x10" part is not processed), and "020" to 20. The hex, oct and dec manipulators behave like %x, %o and %d respectively. I am looking for a general integer input manipulator that works like %i.

Interestingly perhaps the hex manipulator accepts both "0x10" and "10" converting either to 16 decimal.

In case you might be wondering, I am implementing an expression evaluator, and I would like allowed integer operands to be hex, octal, or decimal using the C/C++ prefix convention. The current implementation using sscanf() does this automatically using %i, and I am curious as to whether this could be modified to use iostream without having to explicitly parse the numeric format.

Clifford
  • 88,407
  • 13
  • 85
  • 165
  • Interestin. +1. Wonder if the C++ IOStreams and Locales book has this kind of stuff... – Billy ONeal Dec 18 '10 at 05:38
  • Since I am near 100% certain there is no direct equivalent, I believe the neatest and most in-keeping solution would be to implement a new manipulator of the form `std::ios_base& integer( std::ios_base& str );` – Clifford Dec 18 '10 at 07:18
  • @Johannes has the answer, which also provides the means of implementing the above manipulator. – Clifford Dec 18 '10 at 07:33

2 Answers2

11

The base field in the format flags of basic_istream dictates how to interpret numbers. The field can be set to dec, oct and to hex. By default it's set to dec. If it's set to none of them, basic_istream will behave like scanf's %i flag:

// automatically detect the base, depending on prefix
std::cin.unsetf(std::ios_base::basefield);
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • Genius. Now I see how it is done it is much easier to find the documentation that tells you how! e.g.: http://stdcxx.apache.org/doc/stdlibug/28-3.html – Clifford Dec 18 '10 at 07:28
1

Instead of resetting the basefield directly, a slightly more intuitive solution is to use the setbase(int base) manipulator:

#include <iomanip>
#include <iostream>

int main()
{
  int i;
  std::cin >> std::setbase(0) >> i;
  std::cout << i << std::endl;
}

To quote cppreference:

Values of base other than 8, 10, or 16 reset basefield to zero, which corresponds to decimal output and prefix-dependent input.

Meyer
  • 1,662
  • 7
  • 21
  • 20