By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
454,435 Members | 1,485 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 454,435 IT Pros & Developers. It's quick & easy.

no setw for istreams?

P: n/a
edd
Hello all,

I'm trying to put together some code that reads 3 adjacent pairs of hex
digits from an istream. Each hex digit pair represents a non-negative
integer.

For example I would like to extract 1, 255 and 18 from 01ff12 (as the
components of a simple RGB colour, in my application).

I was hoping to find something like std::setw for istreams and use it
in combination with std::hex so that I could read 2 hex digits at a
time, but as far as I can tell no such entity exists in the C++
standard library.
Is there a neat and tidy way of doing what I want, or am I going to
have to do something nasty like put each digit pair in to its own
buffer and stream-extract/strtoul the numbers from there?

Why is it that no equivalent to setw exists for istreams?

Kind Regards,

Edd

Dec 25 '06 #1
Share this Question
Share on Google+
10 Replies


P: n/a

ed*@nunswithguns.net wrote:
Hello all,

I'm trying to put together some code that reads 3 adjacent pairs of hex
digits from an istream. Each hex digit pair represents a non-negative
integer.

For example I would like to extract 1, 255 and 18 from 01ff12 (as the
components of a simple RGB colour, in my application).

I was hoping to find something like std::setw for istreams and use it
in combination with std::hex so that I could read 2 hex digits at a
time, but as far as I can tell no such entity exists in the C++
standard library.
Is there a neat and tidy way of doing what I want, or am I going to
have to do something nasty like put each digit pair in to its own
buffer and stream-extract/strtoul the numbers from there?

Why is it that no equivalent to setw exists for istreams?

Kind Regards,

Edd
There are a number of ways to approach the issue, and this is not
neccessarily the best way.
You could teach the computer how to count with hex char pairs.
Extracting two chars from a std::istringstream or std::istream& is
dandy but that will get you an ascii translation, not what you need.
The Hex class's const_char_array ctor takes 3 chars, not 2 (because of
null termination).
The cvt(...) function converts each hex digit to an unsigned equivalent
while the ctor(s) init lists take care of calculating the final
unsigned result. Any hex digit that falls out of range generates an
exception.
This should be a portable solution. But that remains to be seen.

#include <iostream>
#include <ostream>
#include <string>
#include <stdexcept>

class Hex
{
char m_16c; // left hex digit * 16
char m_c; // right hex digit
unsigned m_n; // result
public:
Hex(const char (& array)[3]) // ctor, char array[3] by ref
: m_16c(array[0]), m_c(array[1]),
m_n(16*cvt(m_16c) + cvt(m_c)) { }
Hex(std::string& s) // ctor, a string of 2 chars, others ignored
: m_16c(s[0]), m_c(s[1]),
m_n(16*cvt(m_16c) + cvt(m_c)) { }
Hex(const Hex& copy) // copy ctor
{
m_16c = copy.m_16c;
m_c = copy.m_c;
m_n = copy.m_n;
}
// member functions
unsigned cvt(const char c) const
{
if(c >= '0' && c <= '9')
{
return c - '0';
} else if(c >= 'a' && c <= 'f')
{
return 10 + (c - 'a');
} else if(c >= 'A' && c <= 'F')
{
return 10 + (c - 'A');
} else
{
throw std::runtime_error("Hex out of range.");
}
}
// friend operators
friend std::ostream&
operator<<(std::ostream& os, const Hex& r_h)
{
return os << r_h.m_n;
}
};

int main()
{
try {
// testing hex pairs
Hex h255("ff");
std::cout << h255 << std::endl;
Hex h16("10");
std::cout << h16 << std::endl;
Hex h0A("0A");
std::cout << h0A << std::endl;

// parsing a buffer
std::string buffer("ff100a");
std::string red(buffer, 0, 2); // substr
Hex r(red);
std::cout << "r: " << r << std::endl;
std::string green(buffer, 2, 2);
Hex g(green);
std::cout << "g: " << g << std::endl;
std::string blue(buffer, 4, 2);
Hex b(blue);
std::cout << "b: " << b << std::endl;
}
catch(std::exception& r_e)
{
std::cerr << "Error: " << r_e.what();
std::cerr << std::endl;
}
}

/*
255
16
10
r: 255
g: 16
b: 10
*/

Note how the std::string buffer in main() is substringed and loaded
into individual Hex variables.
Imagine a Colour class with 3 Hex members (r, g and b), appropriate
ctors and operator overloads and even a filereader function.
You could open a file with std::ifstream and use std::getline to load
that buffer one line at a time.

Dec 26 '06 #2

P: n/a
edd

Salt_Peter wrote:
There are a number of ways to approach the issue, and this is not
neccessarily the best way.
You could teach the computer how to count with hex char pairs.
Extracting two chars from a std::istringstream or std::istream& is
dandy but that will get you an ascii translation, not what you need.
The Hex class's const_char_array ctor takes 3 chars, not 2 (because of
null termination).
The cvt(...) function converts each hex digit to an unsigned equivalent
while the ctor(s) init lists take care of calculating the final
unsigned result. Any hex digit that falls out of range generates an
exception.
This should be a portable solution. But that remains to be seen.
[ generous code snipped ]

Many thanks for you reply. I had come up with something equally long
winded. I was hoping that istreams would provide a way of doing this
simply as the task appears appropriate for their job description.

In fact, I'm not sure your code is entirely portable. If I'm not
mistaken it appears that you're assuming that all character sets have
alphabetical glyphs with contiguous values (i.e. they could do
aAbBcCdD... as far as I'm aware).

But it just goes to show how stupidly tricky such a problem is. I
really am going to have to peel the characters off in to 2-digit
buffers and read from those :/

Kind regards,

Edd

Dec 26 '06 #3

P: n/a
ed*@nunswithguns.net wrote:
Hello all,

I'm trying to put together some code that reads 3 adjacent pairs of hex
digits from an istream. Each hex digit pair represents a non-negative
integer.

For example I would like to extract 1, 255 and 18 from 01ff12 (as the
components of a simple RGB colour, in my application).

I was hoping to find something like std::setw for istreams and use it
in combination with std::hex so that I could read 2 hex digits at a
time, but as far as I can tell no such entity exists in the C++
standard library.
Is there a neat and tidy way of doing what I want, or am I going to
have to do something nasty like put each digit pair in to its own
buffer and stream-extract/strtoul the numbers from there?

Why is it that no equivalent to setw exists for istreams?
How about reading all six digits as one number from the stream,
using std::hex and then extracting the three components using
the modulo operation?

That would save you the two-digit buffer but probably you
would run into little/big-endian issues.

HTH,
- J.
Dec 26 '06 #4

P: n/a
ed*@nunswithguns.net wrote:
Hello all,

I'm trying to put together some code that reads 3 adjacent pairs of hex
digits from an istream. Each hex digit pair represents a non-negative
integer.

For example I would like to extract 1, 255 and 18 from 01ff12 (as the
components of a simple RGB colour, in my application).

I was hoping to find something like std::setw for istreams and use it
in combination with std::hex so that I could read 2 hex digits at a
time, but as far as I can tell no such entity exists in the C++
standard library.
Is there a neat and tidy way of doing what I want, or am I going to
have to do something nasty like put each digit pair in to its own
buffer and stream-extract/strtoul the numbers from there?

Why is it that no equivalent to setw exists for istreams?

Kind Regards,

Edd
Hello,

Another approach may be to use std::sscanf from <cstdio>:

#include <cstdio>
#include <iostream>
int main()
{
const char* hex("01ff12");
unsigned int R,G,B;
const int n(std::sscanf(hex,"%2x%2x%2x",&R,&G,&B));
if(3!=n)
std::cerr<<n<<" items assigned, it is supposed to be 3.\n";
else
std::cout<<"R="<<R<<",G="<<G<<",B="<<B<<'\n';
}

On my implementation this gives:
R=1,G=255,B=18
Sincerely,

Peter Jansson
http://www.p-jansson.com/
http://www.jansson.net/
Dec 27 '06 #5

P: n/a
edd
Hi Peter,

Peter Jansson wrote:
Hello,

Another approach may be to use std::sscanf from <cstdio>:

#include <cstdio>
#include <iostream>
int main()
{
const char* hex("01ff12");
unsigned int R,G,B;
const int n(std::sscanf(hex,"%2x%2x%2x",&R,&G,&B));
if(3!=n)
std::cerr<<n<<" items assigned, it is supposed to be 3.\n";
else
std::cout<<"R="<<R<<",G="<<G<<",B="<<B<<'\n';
}

On my implementation this gives:
R=1,G=255,B=18
Thanks very much for your response. That's certainly the most concise
way of doing things. However, I'm doing this in a teaching context and
I really don't want to start preaching about the benefits of the type
safety in C++ and then use code that ignores them.

The other niggle is that the interface to the function in the example
code takes an std::istream reference. So before using sscanf I'd have
to read the 6 characters in to a buffer, checking each was a hex digit
before reading the next in order to stay true to how the pre-defined
istream extraction operators work.

Would it be possible to write a custom manipulator to do something like
setw for istreams?

I guess I'm just a bit frustrated that this is one of those times where
I'll have to admit that C++ is deficient in some sense, even though the
task isn't really all that complicated.

Edd

Dec 29 '06 #6

P: n/a
Hello Edd!
ed*@nunswithguns.net wrote:
I was hoping to find something like std::setw for istreams and use it
in combination with std::hex so that I could read 2 hex digits at a
time, but as far as I can tell no such entity exists in the C++
standard library.
It is not readily there but it can be built relatively easily into
a suitable num_get facet (code see below).
Is there a neat and tidy way of doing what I want, or am I going to
have to do something nasty like put each digit pair in to its own
buffer and stream-extract/strtoul the numbers from there?
I would prefer something like the num_get facet described
above...
Why is it that no equivalent to setw exists for istreams?
I don't know about the reasons but those I'd consider to be
most likely could be seen as an insult on some of the more
active committee members. Thus, I'm keeping them for
myself...

Good luck, Denise!
--- CUT HERE ---
#include <iostream>
#include <iomanip>
#include <locale>

class width_num_get:
public std::num_get<char>
{
struct countbuf:
std::streambuf
{
countbuf(std::istreambuf_iterator<charbeg,
std::istreambuf_iterator<charend, int count):
m_beg(beg), m_end(end), m_count(count)
{
}

int underflow()
{
if (this->m_beg == this->m_end || this->m_count == 0)
return traits_type::eof();
--this->m_count;
this->m_buffer = *this->m_beg++;
this->setg(&m_buffer, &m_buffer, &m_buffer + 1);
return traits_type::not_eof(this->m_buffer);
}

std::istreambuf_iterator<charm_beg, m_end;
int m_count;
char m_buffer;
};

private:
iter_type
do_get(iter_type it, iter_type end, std::ios_base& fmt,
std::ios_base::iostate& state, long& val) const
{
return this->get_template(it, end, fmt, state, val);
}
iter_type
do_get(iter_type it, iter_type end, std::ios_base& fmt,
std::ios_base::iostate& state, unsigned short& val) const
{
return this->get_template(it, end, fmt, state, val);
}

iter_type
do_get(iter_type it, iter_type end, std::ios_base& fmt,
std::ios_base::iostate& state, unsigned int& val) const
{
return this->get_template(it, end, fmt, state, val);
}

iter_type
do_get(iter_type it, iter_type end, std::ios_base& fmt,
std::ios_base::iostate& state, unsigned long& val) const
{
return this->get_template(it, end, fmt, state, val);
}
template <typename T>
iter_type
get_template(iter_type it, iter_type end, std::ios_base& fmt,
std::ios_base::iostate& state, T& val) const
{
if (fmt.width() == 0)
return this->std::num_get<char>::do_get(it, end, fmt, state,
val);
countbuf sbuf(it, end, fmt.width(0));

this->std::num_get<char>::do_get(std::istreambuf_iterat or<char>(&sbuf),
std::istreambuf_iterator<char>(),
fmt, state, val);
state &= ~std::ios_base::eofbit;
return sbuf.m_beg;
}
};

int main()
{
std::cin.imbue(std::locale(std::locale(), new width_num_get));
for (short val; std::cin >std::hex >std::setw(2) >val; )
std::cout << "value: 0x" << std::hex << val << "\n";
}

Dec 30 '06 #7

P: n/a
edd
Hello Denise,

Denise Kleingeist wrote:
Why is it that no equivalent to setw exists for istreams?

I don't know about the reasons but those I'd consider to be
most likely could be seen as an insult on some of the more
active committee members. Thus, I'm keeping them for
myself...
Fair enough :)

[ generous code snipped ]

Thanks so much for your code, Denise! I have never used facets before
(explicitly) so I have to admit I don't fully understand it yet. I'm
doing some more reading now!

I'm not sure that code of such a technical nature will make it in to
the teaching notes, but I'm very happy to see that there is a C++
solution! Perhaps I'll include it as an appendix.

At any rate, thank you very much for taking the time to put that
together!

Kind regards,

Edd

Dec 30 '06 #8

P: n/a
"Denise Kleingeist" <de***************@googlemail.comwrote in message
news:11**********************@v33g2000cwv.googlegr oups.com...
>Why is it that no equivalent to setw exists for istreams?

I don't know about the reasons but those I'd consider to be
most likely could be seen as an insult on some of the more
active committee members. Thus, I'm keeping them for
myself...
Probably just as well. In this particular case, the committee did
something rather revolutionary -- it codified existing practice.
Between 1990 and 1997 nobody seems to have complained that the
iostreams package developed in the 1980s was deficient in this
regard, so oddly enough the committee did nothing to change it.

Go figure.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
Dec 30 '06 #9

P: n/a
Hello P.J.!
P.J. Plauger wrote:
"Denise Kleingeist" <de***************@googlemail.comwrote in message
news:11**********************@v33g2000cwv.googlegr oups.com...
Why is it that no equivalent to setw exists for istreams?
I don't know about the reasons but those I'd consider to be
most likely could be seen as an insult on some of the more
active committee members. Thus, I'm keeping them for
myself...

Probably just as well. In this particular case, the committee did
something rather revolutionary -- it codified existing practice.
This is indeed revolutionary! ... considering that IOStream was always
intended as a replacement for stdio and thus should have the same
power, including for the task of parsing input. Someone should have
noted that the existing practice was incomplete and inconsistent
(setw has an effect when reading to a char*).
Between 1990 and 1997 nobody seems to have complained that the
iostreams package developed in the 1980s was deficient in this
regard, so oddly enough the committee did nothing to change it.
There were definitely compaints about the absence of setw support
for istreams (e.g.
<http://groups.google.com/group/comp.std.c++/msg/3cb7faa13ef4d70c>).
Also, at this time there were many experts who strongly argued that
stdio should still be used in C++, e.g. because the efficiency of
widely used implementations of IOStreams was mediocre with
implementers publically arguing that it can't be done differently.
Thus,
many programmers did not use IOStreams and thus didn't realize the
true but correctable deficencies.

As things are for programming languages, the standardization is to
a fair extend setting up precedence on how to use a programming
language. This includes that things often go beyond existing practice
for the benefit of future ease of use. Supporting something like setw
to cover the capabilities of C's stdio input facilities would clearly
fall into this area.

Good luck, Denise!

Dec 30 '06 #10

P: n/a
"Denise Kleingeist" <de***************@googlemail.comwrote in message
news:11**********************@i12g2000cwa.googlegr oups.com...
Hello P.J.!
P.J. Plauger wrote:
>"Denise Kleingeist" <de***************@googlemail.comwrote in message
news:11**********************@v33g2000cwv.googleg roups.com...
>Why is it that no equivalent to setw exists for istreams?

I don't know about the reasons but those I'd consider to be
most likely could be seen as an insult on some of the more
active committee members. Thus, I'm keeping them for
myself...

Probably just as well. In this particular case, the committee did
something rather revolutionary -- it codified existing practice.

This is indeed revolutionary! ... considering that IOStream was always
intended as a replacement for stdio and thus should have the same
power, including for the task of parsing input. Someone should have
noted that the existing practice was incomplete and inconsistent
(setw has an effect when reading to a char*).
Perhaps someone should have, but nobody saw fit to tell the committee.
>Between 1990 and 1997 nobody seems to have complained that the
iostreams package developed in the 1980s was deficient in this
regard, so oddly enough the committee did nothing to change it.

There were definitely compaints about the absence of setw support
for istreams (e.g.
<http://groups.google.com/group/comp.std.c++/msg/3cb7faa13ef4d70c>).
So you think a comment in a newsgroup is sufficient to cause an
overworked committee to undertake a work item to do something
about it? Try spending some time on a standards committee and
see whether your perspective changes.
Also, at this time there were many experts who strongly argued that
stdio should still be used in C++, e.g. because the efficiency of
widely used implementations of IOStreams was mediocre with
implementers publically arguing that it can't be done differently.
I still argue that stdio should be used where it's superior, but
then I'm definitely a pragmatist among idealists in this regard.
Thus,
many programmers did not use IOStreams and thus didn't realize the
true but correctable deficencies.
And so the committee should have been prescient, in the absence
of concrete requests?
As things are for programming languages, the standardization is to
a fair extend setting up precedence on how to use a programming
language. This includes that things often go beyond existing practice
for the benefit of future ease of use. Supporting something like setw
to cover the capabilities of C's stdio input facilities would clearly
fall into this area.
Fine. And who took the trouble to point this out?

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
Dec 30 '06 #11

This discussion thread is closed

Replies have been disabled for this discussion.