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

Convert an integer to a string? Plan B?

P: n/a
http://public.research.att.com/~bs/b...#int-to-string

Is there no C library function that will take an int and convert it to its
ascii representation? The example Bjarne shows in his faq is not extremely
convenient.
--
NOUN:1. Money or property bequeathed to another by will. 2. Something handed
down from an ancestor or a predecessor or from the past: a legacy of
religious freedom. ETYMOLOGY: MidE legacie, office of a deputy, from OF,
from ML legatia, from L legare, to depute, bequeath. www.bartleby.com/61/
Mar 7 '06 #1
Share this Question
Share on Google+
43 Replies


P: n/a
Steven T. Hatton wrote:
http://public.research.att.com/~bs/b...#int-to-string

Is there no C library function that will take an int and convert it to its
ascii representation? The example Bjarne shows in his faq is not extremely
convenient.


sprintf

V
--
Please remove capital As from my address when replying by mail
Mar 7 '06 #2

P: n/a
Steven T. Hatton wrote:
http://public.research.att.com/~bs/b...#int-to-string

Is there no C library function that will take an int and convert it to its
ascii representation? The example Bjarne shows in his faq is not extremely
convenient.


The example Stroustrup gives is the best way. Compare:

http://www.parashift.com/c++-faq-lit....html#faq-39.2
http://www.parashift.com/c++-faq-lit....html#faq-39.3

As the FAQ notes, you could use C facilities rather than C++, but the
latter should be preferred.

See also Boost's lexical_cast.

Cheers! --M

Mar 7 '06 #3

P: n/a
mlimber wrote:

As the FAQ notes, you could use C facilities rather than C++, but the
latter should be preferred.


However, it doesn't say why the "C++" approach should be preferred.
(Yes, I'm aware that it's possible to pass too small an output buffer to
the C functions. Don't do that.)

C provides perfectly good conversion functions. The "C++" approach,
creating a stringstream object which you then throw away, is extremely
expensive. I would never use it.

--

Pete Becker
Roundhouse Consulting, Ltd.
Mar 7 '06 #4

P: n/a
mlimber wrote:
The example Stroustrup gives is the best way. Compare:

http://www.parashift.com/c++-faq-lit....html#faq-39.2
http://www.parashift.com/c++-faq-lit....html#faq-39.3

As the FAQ notes, you could use C facilities rather than C++, but the
latter should be preferred.

See also Boost's lexical_cast.

Cheers! --M


The whole idea is to have one little call such as itos there when you need
it. I usually want to do it in a situation such as :

virtual const char* what() const throw() {
std::string message(_myName);
message+="\n\t";
message+=""!=_namespaceName? _namespaceName+"::":"";
message+=""!=_className ? _className +"::":"";

message+=""!=_file?" File: "+_file :"";
message+= 0!=_line?" Line: "+itos(_line):"";

message+=_message;

return message.toStdString().c_str();
}
Note that I have not yet tested this with std::string. I am converting code
that used Qt QString, which provides a QString::setNum(int).
--
NOUN:1. Money or property bequeathed to another by will. 2. Something handed
down from an ancestor or a predecessor or from the past: a legacy of
religious freedom. ETYMOLOGY: MidE legacie, office of a deputy, from OF,
from ML legatia, from L legare, to depute, bequeath. www.bartleby.com/61/
Mar 7 '06 #5

P: n/a
Pete Becker wrote:
C provides perfectly good conversion functions.
.... which are harder to use than might seem. Both the buffer size
and the conversion specifiers are potential stumbling blocks. Of
course, any experienced C programmers knows these.
The "C++" approach,
creating a stringstream object which you then throw away, is extremely
expensive. I would never use it.


It is actually a shame that there is no simple and efficient method
addressing this issue. Of course, what actually qualifies as simple
and/or efficient depends on the user's view. I would use something
like the code below:

#include <algorithm>
#include <limits>

template <typename V, typename OutIt>
OutIt convert(V v, OutIt to)
{
enum { bsize = std::numeric_limits<V>::digits10 + 2 };
bool neg = v < 0;

char buffer[bsize], *tmp = buffer + bsize;
*--tmp = "0123456789"[(neg? -(v + (v < -10? 10: 0)): v) % 10];
v /= 10;

if (neg)
v = -v;

for (; v > 0; v /= 10)
*--tmp = "0123456789"[v % 10];

if (neg)
*--tmp = '-';
return std::copy(tmp, buffer + bsize, to);
}

Of course, when used with an inappropriate iterator it also gives
the potential of a buffer overrun. ... but it also allows for
perfectly save use e.g. when using 'std::back_inserter()' together
with an 'std::string' as the destination.
--
<mailto:di***********@yahoo.com> <http://www.dietmar-kuehl.de/>
<http://www.eai-systems.com> - Efficient Artificial Intelligence
Mar 7 '06 #6

P: n/a
In article <5N******************************@speakeasy.net> ,
"Steven T. Hatton" <ch********@germania.sup> wrote:
http://public.research.att.com/~bs/b...#int-to-string

Is there no C library function that will take an int and convert it to its
ascii representation? The example Bjarne shows in his faq is not extremely
convenient.


How could it be any more convenient?

template < typename T, typename U >
T lexical_cast( const U& u ) {
std::stringstream ss;
T t;
if ( !( ss << u && ss >> t ) ) throw std::bad_cast();
return t;
}

The above can be used exactly like any of the other casting operators
that C++ provides. Boost provides a much more optimized version if you
find it necessary.

--
Magic depends on tradition and belief. It does not welcome observation,
nor does it profit by experiment. On the other hand, science is based
on experience; it is open to correction by observation and experiment.
Mar 7 '06 #7

P: n/a
In article <ps********************@giganews.com>,
Pete Becker <pe********@acm.org> wrote:
mlimber wrote:

As the FAQ notes, you could use C facilities rather than C++, but the
latter should be preferred.

However, it doesn't say why the "C++" approach should be preferred.
(Yes, I'm aware that it's possible to pass too small an output buffer to
the C functions. Don't do that.)


Passing a too small buffer, and type safety are the two reasons I can
think of off hand, there may be more.

When it comes down to it, the C++ approach has less undefined behavior.
In order to "just don't do that" one must know all the things that one
shouldn't do. Obviously, the fewer things there are, the easer it will
be to not do them.

C provides perfectly good conversion functions.
"perfectly"? I think "adequate" would be a more appropriate adjective,
as in "barely sufficient or satisfactory". But that's just me, YMMV.

The "C++" approach,
creating a stringstream object which you then throw away, is extremely
expensive. I would never use it.


I use stringstreams for this purpose all over my code and I've never had
a user complain that it's too slow because of it. Yes, I've written code
that's "too slow", that's part of the nature of writing games, but
profiling showed other parts of the code that were far more expensive
than stringstreams.
--
Magic depends on tradition and belief. It does not welcome observation,
nor does it profit by experiment. On the other hand, science is based
on experience; it is open to correction by observation and experiment.
Mar 7 '06 #8

P: n/a

"Steven T. Hatton" <ch********@germania.sup> skrev i meddelandet
news:b6******************************@speakeasy.ne t...
mlimber wrote:
The example Stroustrup gives is the best way. Compare:

http://www.parashift.com/c++-faq-lit....html#faq-39.2
http://www.parashift.com/c++-faq-lit....html#faq-39.3

As the FAQ notes, you could use C facilities rather than C++, but
the
latter should be preferred.

See also Boost's lexical_cast.

Cheers! --M


The whole idea is to have one little call such as itos there when
you need
it. I usually want to do it in a situation such as :

virtual const char* what() const throw() {
std::string message(_myName);
message+="\n\t";
message+=""!=_namespaceName? _namespaceName+"::":"";
message+=""!=_className ? _className +"::":"";

message+=""!=_file?" File: "+_file :"";
message+= 0!=_line?" Line: "+itos(_line):"";

message+=_message;

return message.toStdString().c_str();
}
Note that I have not yet tested this with std::string.


No, obviously! :-)

This is exactly why using C style char pointers are so dangerous. As
soon as the function returns, the message goes out of scope, and is
destroyed.

Guess what happens to the pointer?
(You also cannot say that what() doesn't throw, when any of the string
operations might throw a bad_alloc.)
Bo Persson


Mar 7 '06 #9

P: n/a
Daniel T. wrote:
In article <ps********************@giganews.com>,
Pete Becker <pe********@acm.org> wrote:

mlimber wrote:
As the FAQ notes, you could use C facilities rather than C++, but the
latter should be preferred.

However, it doesn't say why the "C++" approach should be preferred.
(Yes, I'm aware that it's possible to pass too small an output buffer to
the C functions. Don't do that.)

Passing a too small buffer,


Yup. You have to know something about conversions to get conversions right.
and type safety are the two reasons I can
think of off hand,
We're talking about converting an int. Write it once, get it right, end
of discussion.
there may be more.
There may not be. Doesn't affect this discussion.

When it comes down to it, the C++ approach has less undefined behavior.
Nope. Write it once, get it right. No undefined behavior.

Oh, you meant "less opportunity to screw up if you're careless". Well,
that's true. Programming isn't a job for careless people.
In order to "just don't do that" one must know all the things that one
shouldn't do. Obviously, the fewer things there are, the easer it will
be to not do them.
Easier isn't the only goal, especially when any competent programmer
ought to be able to convert an int to a string with very little effort.
The "C++" approach,
creating a stringstream object which you then throw away, is extremely
expensive. I would never use it.

I use stringstreams for this purpose all over my code and I've never had
a user complain that it's too slow because of it. Yes, I've written code
that's "too slow", that's part of the nature of writing games, but
profiling showed other parts of the code that were far more expensive
than stringstreams.


Gratuitously slow code isn't good design. The reasons for using a
stringstream simply aren't compelling, and the cost is high. If you
don't put the slow stuff in, you won't have to take it out later.

--

Pete Becker
Roundhouse Consulting, Ltd.
Mar 7 '06 #10

P: n/a
Daniel T. wrote:
In article <5N******************************@speakeasy.net> ,
"Steven T. Hatton" <ch********@germania.sup> wrote:
http://public.research.att.com/~bs/b...#int-to-string

Is there no C library function that will take an int and convert it to
its
ascii representation? The example Bjarne shows in his faq is not
extremely convenient.


How could it be any more convenient?

template < typename T, typename U >
T lexical_cast( const U& u ) {
std::stringstream ss;
T t;
if ( !( ss << u && ss >> t ) ) throw std::bad_cast();
return t;
}

The above can be used exactly like any of the other casting operators
that C++ provides. Boost provides a much more optimized version if you
find it necessary.


It's just one of those little things I would expect to have in the Standard
Library which isn't there. It's good to know it's in boost. At least that
is a more or less standard resource.
--
NOUN:1. Money or property bequeathed to another by will. 2. Something handed
down from an ancestor or a predecessor or from the past: a legacy of
religious freedom. ETYMOLOGY: MidE legacie, office of a deputy, from OF,
from ML legatia, from L legare, to depute, bequeath. www.bartleby.com/61/
Mar 7 '06 #11

P: n/a
Bo Persson wrote:

"Steven T. Hatton" <ch********@germania.sup> skrev i meddelandet
news:b6******************************@speakeasy.ne t...
mlimber wrote:
The example Stroustrup gives is the best way. Compare:

http://www.parashift.com/c++-faq-lit....html#faq-39.2 http://www.parashift.com/c++-faq-lit....html#faq-39.3
As the FAQ notes, you could use C facilities rather than C++, but
the
latter should be preferred.

See also Boost's lexical_cast.

Cheers! --M
The whole idea is to have one little call such as itos there when
you need
it. I usually want to do it in a situation such as :

virtual const char* what() const throw() {
std::string message(_myName);
message+="\n\t";
message+=""!=_namespaceName? _namespaceName+"::":"";
message+=""!=_className ? _className +"::":"";

message+=""!=_file?" File: "+_file :"";
message+= 0!=_line?" Line: "+itos(_line):"";

message+=_message;

return message.toStdString().c_str();
}
Note that I have not yet tested this with std::string.


No, obviously! :-)

This is exactly why using C style char pointers are so dangerous. As
soon as the function returns, the message goes out of scope, and is
destroyed.

Guess what happens to the pointer?


Well, the alternative is to have message be a class member that goes out of
scope at some unpredictable point in the user's environment. Technically,
I believe the c_str() data is fair game if it is used immediately upon
return of the what() function.

(You also cannot say that what() doesn't throw, when any of the string
operations might throw a bad_alloc.)


I guess I will have to swallow such an exception, and hope it doesn't kill
me. I could use all C string functions, but that would simply be evading
the issue. If I do happen to get a bad_alloc I'm hosed anyway. Perhaps I
just do a catch(const std::bad_alloc& ba) { return ba.what(); }

--
NOUN:1. Money or property bequeathed to another by will. 2. Something handed
down from an ancestor or a predecessor or from the past: a legacy of
religious freedom. ETYMOLOGY: MidE legacie, office of a deputy, from OF,
from ML legatia, from L legare, to depute, bequeath. www.bartleby.com/61/
Mar 7 '06 #12

P: n/a
Steven T. Hatton wrote
The whole idea is to have one little call such as itos there when you need
it. I usually want to do it in a situation such as :

virtual const char* what() const throw() {
std::string message(_myName);
message+="\n\t";
message+=""!=_namespaceName? _namespaceName+"::":"";
message+=""!=_className ? _className +"::":"";

message+=""!=_file?" File: "+_file :"";
message+= 0!=_line?" Line: "+itos(_line):"";

message+=_message;

return message.toStdString().c_str();
}
Note that I have not yet tested this with std::string. I am converting code
that used Qt QString, which provides a QString::setNum(int).


Exactly this is what stringstreams are invented for!!

int some_integer=125;
std::ostringstream os;
os <<"\n\t"
<< ""!=_namespaceName? _namespaceName+"::":""
<< some_integer
<< _message;
return os.str();

You don't need a special conversion routine here, since the automatic
conversion from ints to strings is done by the magic of streams.
Mar 8 '06 #13

P: n/a
Christian Gollwitzer wrote:
Steven T. Hatton wrote
The whole idea is to have one little call such as itos there when you
need
it. I usually want to do it in a situation such as :

virtual const char* what() const throw() {
std::string message(_myName);
message+="\n\t";
message+=""!=_namespaceName? _namespaceName+"::":"";
message+=""!=_className ? _className +"::":"";

message+=""!=_file?" File: "+_file :"";
message+= 0!=_line?" Line: "+itos(_line):"";

message+=_message;

return message.toStdString().c_str();
}
Note that I have not yet tested this with std::string. I am converting
code that used Qt QString, which provides a QString::setNum(int).


Exactly this is what stringstreams are invented for!!

int some_integer=125;
std::ostringstream os;
os <<"\n\t"
<< ""!=_namespaceName? _namespaceName+"::":""
<< some_integer
<< _message;
return os.str();

You don't need a special conversion routine here, since the automatic
conversion from ints to strings is done by the magic of streams.


In this case it is true. However, in the other parts of the code I make the
conversion in a function call.
--
NOUN:1. Money or property bequeathed to another by will. 2. Something handed
down from an ancestor or a predecessor or from the past: a legacy of
religious freedom. ETYMOLOGY: MidE legacie, office of a deputy, from OF,
from ML legatia, from L legare, to depute, bequeath. www.bartleby.com/61/
Mar 11 '06 #14

P: n/a

Pete Becker wrote:
Daniel T. wrote:
In article <ps********************@giganews.com>,
Pete Becker <pe********@acm.org> wrote:

mlimber wrote:

As the FAQ notes, you could use C facilities rather than C++, but the
latter should be preferred.
However, it doesn't say why the "C++" approach should be preferred.
(Yes, I'm aware that it's possible to pass too small an output buffer to
the C functions. Don't do that.)

Passing a too small buffer,


Yup. You have to know something about conversions to get conversions right.


This is worrying. What about the C++ aim to help occasional and novice
programmers? (which is very relevent to this newsgroup BTW)?

To be portable you would either have to #ifdef dependent on platform or
make sure that your buffer would hold the largest possible int at least
till it gets bigger. I assume that your own stringent performance
standards wouldnt consider allowing you to waste stack space so you'd
have to use some sort of sizeof and then calculate either manually or
in code which means checking its correct, bearing in mind terminators,-
signs etc, similarly write a long et al version too and try to call the
right version (see below). In fact its pretty tedious to do all that
and check its correct and now what are you going to do with the char
array result anyway? Why bother? Let an ostringstream do the work and
spend brain power on more important things.

The other major advantage (apart from the very important one of
automatic resource management) of a stringstream is that you can make
the integer type a template parameter, which means it beats your write
once rule as using C functions you would need to rewrite for long and
unsigned long, double and float, all which may have different lengths
of ascii representation afaik.
and type safety are the two reasons I can
think of off hand,


We're talking about converting an int. Write it once, get it right, end
of discussion.


Then do same for a long, an unsigned long, a float, a double etc etc...
Then check all your buffer lengths... etc etc.
there may be more.


There may not be. Doesn't affect this discussion.

When it comes down to it, the C++ approach has less undefined behavior.


Nope. Write it once, get it right. No undefined behavior.

Oh, you meant "less opportunity to screw up if you're careless". Well,
that's true. Programming isn't a job for careless people.


If you have never made a careless mistake in your code then you must be
exceptional, but if only people that have never made coding mistakes
are allowed to code C++ I think the language is dead and you may soon
be the only C++ programmer. No offence to anyone else that has never
made a typo intended of course.

Of course then there would be no need for diagnostics from the compiler
as you and the other perfect programmer dont need them.

Again what about making the language accessible to occasional and
novice programmers?
In order to "just don't do that" one must know all the things that one
shouldn't do. Obviously, the fewer things there are, the easer it will
be to not do them.


Easier isn't the only goal, especially when any competent programmer
ought to be able to convert an int to a string with very little effort.


Easier and catching mistakes are very important goals. Thats basically
what high level programming is all about.
The "C++" approach,
creating a stringstream object which you then throw away, is extremely
expensive. I would never use it.

I use stringstreams for this purpose all over my code and I've never had
a user complain that it's too slow because of it. Yes, I've written code
that's "too slow", that's part of the nature of writing games, but
profiling showed other parts of the code that were far more expensive
than stringstreams.


I use them too. They are very convenient IMO.

regards
Andy Little

Mar 11 '06 #15

P: n/a
an**@servocomm.freeserve.co.uk wrote:

This is worrying. What about the C++ aim to help occasional and novice
programmers? (which is very relevent to this newsgroup BTW)?

There is a proposal to provide simple, efficient conversion functions.
To be portable you would either have to #ifdef dependent on platform or
make sure that your buffer would hold the largest possible int at least
till it gets bigger.
That's what INT_MAX, etc. are for.
I assume that your own stringent performance
standards wouldnt consider allowing you to waste stack space so you'd
have to use some sort of sizeof and then calculate either manually or
in code which means checking its correct, bearing in mind terminators,-
signs etc, similarly write a long et al version too and try to call the
right version (see below). In fact its pretty tedious to do all that
and check its correct and now what are you going to do with the char
array result anyway? Why bother? Let an ostringstream do the work and
spend brain power on more important things.

This is a big problem in programming today: so many applications are so
big and slow.
The other major advantage (apart from the very important one of
automatic resource management) of a stringstream is that you can make
the integer type a template parameter, which means it beats your write
once rule as using C functions you would need to rewrite for long and
unsigned long, double and float, all which may have different lengths
of ascii representation afaik.

and type safety are the two reasons I can
think of off hand,
We're talking about converting an int. Write it once, get it right, end
of discussion.

Then do same for a long, an unsigned long, a float, a double etc etc...
Then check all your buffer lengths... etc etc.


No, the question was about converting an integer.

If you have never made a careless mistake in your code then you must be
exceptional, but if only people that have never made coding mistakes
are allowed to code C++ I think the language is dead and you may soon
be the only C++ programmer.


I've certainly made my share of careless mistakes. The way to eliminate
them is to catch them with appropriate tests, not write big, slow code
in the hope that it will overwhelm them.

--

Pete Becker
Roundhouse Consulting, Ltd.
Mar 11 '06 #16

P: n/a

Pete Becker wrote:
This is a big problem in programming today: so many applications are so
big and slow.


Reducing size of a C++ application really needs standardisation of
DLL's. The standard library is not large enough or comprehensive enough
so everyone is always reinventing the wheel. Combine large standard
library and put parts in DLL's would have a great impact on size at
least. Smaller apps need to swap to disk less so might even help speed
too.

regards
Andy Little

Mar 11 '06 #17

P: n/a
In article <-_******************************@giganews.com>,
Pete Becker <pe********@acm.org> wrote:
an**@servocomm.freeserve.co.uk wrote:

I assume that your own stringent performance
standards wouldnt consider allowing you to waste stack space so you'd
have to use some sort of sizeof and then calculate either manually or
in code which means checking its correct, bearing in mind terminators,-
signs etc, similarly write a long et al version too and try to call the
right version (see below). In fact its pretty tedious to do all that
and check its correct and now what are you going to do with the char
array result anyway? Why bother? Let an ostringstream do the work and
spend brain power on more important things.


This is a big problem in programming today: so many applications are so
big and slow.


That doesn't mean they are big and slow because stringstream is used for
conversions. Nice straw man there.

and type safety are the two reasons I can
think of off hand,

We're talking about converting an int. Write it once, get it right, end
of discussion.

Then do same for a long, an unsigned long, a float, a double etc etc...
Then check all your buffer lengths... etc etc.


No, the question was about converting an integer.


You've got me there. So many programers need to convert int to strings,
but no one never needs to convert any other type to a string...

If you have never made a careless mistake in your code then you must be
exceptional, but if only people that have never made coding mistakes
are allowed to code C++ I think the language is dead and you may soon
be the only C++ programmer.


I've certainly made my share of careless mistakes. The way to eliminate
them is to catch them with appropriate tests, not write big, slow code
in the hope that it will overwhelm them.


So, what is the "appropriate test" to ensure that a buffer is not
overrun? What is an "appropriate test" to ensure that the type matches
the "type" in the char array passed into sprintf?

The fact is, writing passed the end of a buffer causes undefined
behavior, therefore there is *no* way to test it because there is no
defined result to test for.
--
Magic depends on tradition and belief. It does not welcome observation,
nor does it profit by experiment. On the other hand, science is based
on experience; it is open to correction by observation and experiment.
Mar 11 '06 #18

P: n/a
Daniel T. wrote:
In article <-_******************************@giganews.com>,
Pete Becker <pe********@acm.org> wrote:

an**@servocomm.freeserve.co.uk wrote:
I assume that your own stringent performance
standards wouldnt consider allowing you to waste stack space so you'd
have to use some sort of sizeof and then calculate either manually or
in code which means checking its correct, bearing in mind terminators,-
signs etc, similarly write a long et al version too and try to call the
right version (see below). In fact its pretty tedious to do all that
and check its correct and now what are you going to do with the char
array result anyway? Why bother? Let an ostringstream do the work and
spend brain power on more important things.

This is a big problem in programming today: so many applications are so
big and slow.

That doesn't mean they are big and slow because stringstream is used for
conversions.


There is a great deal more in the paragraph that I quoted than the
mention of ostringstream. Applications are often big and slow because of
the analysis that ends with "why bother".

>and type safety are the two reasons I can
>think of off hand,

We're talking about converting an int. Write it once, get it right, end
of discussion.
Then do same for a long, an unsigned long, a float, a double etc etc...
Then check all your buffer lengths... etc etc.

No, the question was about converting an integer.

You've got me there. So many programers need to convert int to strings,
but no one never needs to convert any other type to a string...


When someone asks about how to convert an integer to a string, it's
overkill to design an enter numeric formatting package.
So, what is the "appropriate test" to ensure that a buffer is not
overrun?
Check its size before you write to it. If you can't do that then you may
have a design error. In the case of a function that formats an integer
value into a local character array, ensuring that the array is large
enough is trivial.
What is an "appropriate test" to ensure that the type matches
the "type" in the char array passed into sprintf?
How did sprintf get into this? Anyway, if you use sprintf, the way you
check it is you inspect the code, or you use a compiler that checks the
argument types against the format specifiers.

The fact is, writing passed the end of a buffer causes undefined
behavior, therefore there is *no* way to test it because there is no
defined result to test for.


First, the fact that the behavior is undefined doesn't mean that there
is no way to test for it. It means that there may not be an obvious,
portable way to test for it. In practice, there are many ways to do
those tests. Debugging implementations have been doing this for years.

Second, you don't test for writing past the end of a buffer. You test
that your buffer is large enough to hold the result, or you prove ab
initio that it is.

--

Pete Becker
Roundhouse Consulting, Ltd.
Mar 11 '06 #19

P: n/a
On Sat, 11 Mar 2006 11:11:57 -0500, Pete Becker <pe********@acm.org>
wrote:
Daniel T. wrote:
So, what is the "appropriate test" to ensure that a buffer is not
overrun?


Here's a proposal for a simple, efficient, and safe conversion
function:

#include <stdio.h>
#include <string>

inline std::string& itostr (int i, std::string& out) {
std::string::value_type buf[128];
int len = snprintf(buf, sizeof(buf), "%d", i);

if (len > 0 && size_t (len) < sizeof (buf)) {
out.assign(buf, std::string::size_type (len));
} else {
out.clear();
}
return out;
}

Regards,
Roland Pibinger
Mar 11 '06 #20

P: n/a
Roland Pibinger wrote:
On Sat, 11 Mar 2006 11:11:57 -0500, Pete Becker <pe********@acm.org>
wrote:
Daniel T. wrote:
So, what is the "appropriate test" to ensure that a buffer is not
overrun?


Here's a proposal for a simple, efficient, and safe conversion
function:

#include <stdio.h>
#include <string>

inline std::string& itostr (int i, std::string& out) {
std::string::value_type buf[128];
int len = snprintf(buf, sizeof(buf), "%d", i);

if (len > 0 && size_t (len) < sizeof (buf)) {
out.assign(buf, std::string::size_type (len));
} else {
out.clear();
}
return out;
}


Seems good to me. I reckon you could maybe improve on the buffer size
could you as below? Whether the function should assert or throw an
exception on failure is another debate too of course, and whether to
check for the terminator etc :

#include <cstdio>
#include <limits>
#include <string>
#include <stdexcept>

struct itostr_error : public std::exception{
itostr_error(){}
const char* what(){ return "bad itostr";}
};
inline
std::string& itostr (int i, std::string& out)
{
std::string::value_type buf[std::numeric_limits<int>::digits10 +
3];
int len = std::sprintf(buf, "%d", i); //slightly quicker
if (len > 0 && size_t (len) < sizeof (buf)
&& (buf[std::numeric_limits<int>::digits10 + 2]=='\0')) {
out.assign(buf, std::string::size_type (len));
return out;
} else {
throw itostr_error();
}
}

#include <iostream>
int main()
{
try{
std::string str;
itostr(INT_MIN,str);
std::cout << str <<'\n';
}
catch( itostr_error & e){
std::cout << e.what() <<'\n';
}
}

regards
Andy Little

Mar 11 '06 #21

P: n/a
an**@servocomm.freeserve.co.uk wrote:

Whether the function should assert or throw an
exception on failure is another debate too


No, it's not. <g> It's a matter of looking at the design of the
application it's going to be used in.

But in general, low level functions should report errors in-channel,
because once you've added the overhead of throwing exceptions you can't
get rid of it. Applications that don't use exceptions shouldn't have to
pay for them. So this sort of thing ought to be written in two layers,
one to do the formatting and report errors, and one that calls it and
translates errors into exceptions.

char *itoc(char *buf, size_t size_if_you_insist, int val)
{
format val into buf
if successful, return next position in buf, otherwise return 0
}

string itostr(int val)
{
char buf[whatever];
if (itoc(buf, whatever, val))
return string(buf);
throw error;
}

--

Pete Becker
Roundhouse Consulting, Ltd.
Mar 11 '06 #22

P: n/a
an**@servocomm.freeserve.co.uk wrote:

[...]
struct itostr_error : public std::exception{
itostr_error(){}
const char* what(){ return "bad itostr";}
};
inline
std::string& itostr (int i, std::string& out)
{
std::string::value_type buf[std::numeric_limits<int>::digits10 +
3];
int len = std::sprintf(buf, "%d", i); //slightly quicker
if (len > 0 && size_t (len) < sizeof (buf)
&& (buf[std::numeric_limits<int>::digits10 + 2]=='\0')) {


BTW The last line above now looks decidedly dodgy, but I dont know the
spec well enough to know if its a potential error, though it slightly
surprisingly doesnt seem to throw an exception on input of e.g 1 on
two systems. Might be best to change it to: &&(buf[len]=='\0')){

regards
Andy Little

Mar 11 '06 #23

P: n/a

Pete Becker wrote:
an**@servocomm.freeserve.co.uk wrote:

Whether the function should assert or throw an
exception on failure is another debate too
No, it's not. <g> It's a matter of looking at the design of the
application it's going to be used in.

But in general, low level functions should report errors in-channel,
because once you've added the overhead of throwing exceptions you can't
get rid of it. Applications that don't use exceptions shouldn't have to
pay for them.


I put them in because I do use them. If an empty string is returned
that is an error and must be acknowledged as such rather than ignored,
which is what happens IMO all to often if it can be ignored.
Embarassing as it is is users must be informed when output is invalid
even if in worst case the application shuts down to indicate its
mangled their data.

(The same is true in critical embedded systems AFAIK except that the
error must be dealt with in place or the alarm sounds and everybody
runs for it, nevertheless in all cases it must be made impossible to
ignore corrupted data)

So this sort of thing ought to be written in two layers, one to do the formatting and report errors, and one that calls it and
translates errors into exceptions.

char *itoc(char *buf, size_t size_if_you_insist, int val)
{
format val into buf
if successful, return next position in buf, otherwise return 0


^^^^^^^^^^^^^^^^^^^^^^^^^

What are we doing here? ... iterating char by char ... seems a little
slow, hardly inlinable surely? ... hmm what about using a stringstream
?

;-)

regards
Andy Little

Mar 11 '06 #24

P: n/a
On 11 Mar 2006 14:19:21 -0800, an**@servocomm.freeserve.co.uk wrote:
Pete Becker wrote:
But in general, low level functions should report errors in-channel,
because once you've added the overhead of throwing exceptions you can't
get rid of it. Applications that don't use exceptions shouldn't have to
pay for them.


I put them in because I do use them. If an empty string is returned
that is an error and must be acknowledged as such rather than ignored,
which is what happens IMO all to often if it can be ignored.


Actually, the conversion from int to string cannot fail because all
bit combinations in an int result in a valid value. The only
'exception' is an out-of-memory condition but that's a different
question (you cannot handle OOM with exceptions). The error handling
code is only included to acknowledge the return value of snprintf.
BTW, the conversion functions are of course not symmetric (string to
int can fail).

Best wishes,
Roland Pibinger
Mar 11 '06 #25

P: n/a
On 11 Mar 2006 13:03:33 -0800, an**@servocomm.freeserve.co.uk wrote:
inline
std::string& itostr (int i, std::string& out)
{
std::string::value_type buf[std::numeric_limits<int>::digits10 +
3];
int len = std::sprintf(buf, "%d", i); //slightly quicker
if (len > 0 && size_t (len) < sizeof (buf)
&& (buf[std::numeric_limits<int>::digits10 + 2]=='\0')) {


What means std::numeric_limits<int>::digits10 and why is it 9 on a 32
bit system?

Roland Pibinger

Mar 11 '06 #26

P: n/a
an**@servocomm.freeserve.co.uk wrote:

char *itoc(char *buf, size_t size_if_you_insist, int val)
{
format val into buf
if successful, return next position in buf, otherwise return 0

^^^^^^^^^^^^^^^^^^^^^^^^^

What are we doing here? ... iterating char by char


No, formatting the text into a buffer and returning the _next_ position
in the buffer, i.e. the one after the formatted text. That makes it easy
to continue to append to the buffer.

--

Pete Becker
Roundhouse Consulting, Ltd.
Mar 12 '06 #27

P: n/a

Roland Pibinger wrote:
On 11 Mar 2006 13:03:33 -0800, an**@servocomm.freeserve.co.uk wrote:
inline
std::string& itostr (int i, std::string& out)
{
std::string::value_type buf[std::numeric_limits<int>::digits10 +
3];
int len = std::sprintf(buf, "%d", i); //slightly quicker
if (len > 0 && size_t (len) < sizeof (buf)
&& (buf[std::numeric_limits<int>::digits10 + 2]=='\0')) {


What means std::numeric_limits<int>::digits10 and why is it 9 on a 32
bit system?


It means that you will get a maximum of digits10 + 1 digits for the
type. Don't ask me why its +1. Try this program to make it clearer.
Just count the number of digits shown by each number and compare that
with digits10 value + 1
#include <limits>
#include <iostream>

template <typename T>
void func()
{
std::cout << std::numeric_limits<T>::digits10 << '\n';
std::cout << std::numeric_limits<T>::max() << '\n';
}

int main()
{

func<short>();
func<unsigned short>();
func<int>();
func<unsigned int>();
func<long>();
func<unsigned long>();
func<long long>();
func<unsigned long long>();
}

regards
Andy Little

Mar 12 '06 #28

P: n/a

Roland Pibinger wrote:
On 11 Mar 2006 14:19:21 -0800, an**@servocomm.freeserve.co.uk wrote:
Pete Becker wrote:
But in general, low level functions should report errors in-channel,
because once you've added the overhead of throwing exceptions you can't
get rid of it. Applications that don't use exceptions shouldn't have to
pay for them.
I put them in because I do use them. If an empty string is returned
that is an error and must be acknowledged as such rather than ignored,
which is what happens IMO all to often if it can be ignored.


Actually, the conversion from int to string cannot fail because all
bit combinations in an int result in a valid value. The only
'exception' is an out-of-memory condition but that's a different
question (you cannot handle OOM with exceptions). The error handling
code is only included to acknowledge the return value of snprintf.


In that case things are much simpler. Now I added a traits class for
the format string so potentially extending the useage to other integer
types, though it seems sprintf is a bit limited to signed and unsigned
int only..whatever...

#include <cstdio>
#include <limits>
#include <string>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_integral.hpp>

template <typename IntegerType>
struct format;

template <>
struct format<int>{
static const char* specifier(){return "%d";}
};
template <>
struct format<unsigned int>{
static const char* specifier(){return "%u";}
};

template <typename IntegerType>
inline
typename boost::enable_if<
boost::is_integral<IntegerType>,
std::string&::type

itostr (IntegerType i, std::string& out)
{
std::string::value_type buf[
std::numeric_limits<IntegerType>::digits10 + 3
];
std::string::size_type len
= std::sprintf(buf, format<IntegerType>::specifier(), i);
out.assign(buf,len);
return out;
}

#include <iostream>
int main()
{
std::string str;
itostr(-1,str);
std::cout << str <<'\n';
itostr(1U,str);
std::cout << str <<'\n';
}

regards
Andy Little

Mar 12 '06 #29

P: n/a
In article <44**************@news.utanet.at>,
rp*****@yahoo.com (Roland Pibinger) wrote:
On Sat, 11 Mar 2006 11:11:57 -0500, Pete Becker <pe********@acm.org>
wrote:
Daniel T. wrote:
So, what is the "appropriate test" to ensure that a buffer is not
overrun?


Here's a proposal for a simple, efficient, and safe conversion
function:

#include <stdio.h>
#include <string>

inline std::string& itostr (int i, std::string& out) {
std::string::value_type buf[128];
int len = snprintf(buf, sizeof(buf), "%d", i);

if (len > 0 && size_t (len) < sizeof (buf)) {
out.assign(buf, std::string::size_type (len));
} else {
out.clear();
}
return out;
}


Why put a 128 char buffer on the stack when string already has one
imbedded in it...

string& itostr( int i, string& result )
{
result.clear();
if ( i == INT_MIN ) {
result += "-2147483648";
}
else if ( i == 0 ) {
result = '0';
}
else {
string::size_type pos = 0;
if ( i < 0 ) {
result = '-';
i = -i;
pos = 1;
}
while ( i > 0 ) {
result.insert( pos, 1, char( '0' + i % 10 ) );
i /= 10;
}
}
return result;
}

string itostr( int i ) {
string result;
itostr( i, result );
return result;
}
--
Magic depends on tradition and belief. It does not welcome observation,
nor does it profit by experiment. On the other hand, science is based
on experience; it is open to correction by observation and experiment.
Mar 12 '06 #30

P: n/a
Roland Pibinger wrote:
On 11 Mar 2006 14:19:21 -0800, an**@servocomm.freeserve.co.uk wrote:
Pete Becker wrote:
But in general, low level functions should report errors in-channel,
because once you've added the overhead of throwing exceptions you can't
get rid of it. Applications that don't use exceptions shouldn't have to
pay for them.


I put them in because I do use them. If an empty string is returned
that is an error and must be acknowledged as such rather than ignored,
which is what happens IMO all to often if it can be ignored.


Actually, the conversion from int to string cannot fail because all
bit combinations in an int result in a valid value.

[snip]

Clause [3.9.1/1] makes that guarantee for unsigned character types. For the
type int, however, I think no such guarantee is made in the standard.
Best

Kai-Uwe Bux

Mar 12 '06 #31

P: n/a

Daniel T. wrote:
In article <44**************@news.utanet.at>,
rp*****@yahoo.com (Roland Pibinger) wrote:
On Sat, 11 Mar 2006 11:11:57 -0500, Pete Becker <pe********@acm.org>
wrote:
Daniel T. wrote:
> So, what is the "appropriate test" to ensure that a buffer is not
> overrun?


Here's a proposal for a simple, efficient, and safe conversion
function:

#include <stdio.h>
#include <string>

inline std::string& itostr (int i, std::string& out) {
std::string::value_type buf[128];
int len = snprintf(buf, sizeof(buf), "%d", i);

if (len > 0 && size_t (len) < sizeof (buf)) {
out.assign(buf, std::string::size_type (len));
} else {
out.clear();
}
return out;
}


Why put a 128 char buffer on the stack when string already has one
imbedded in it...

string& itostr( int i, string& result )
{
result.clear();
if ( i == INT_MIN ) {
result += "-2147483648";
}
else if ( i == 0 ) {
result = '0';
}
else {
string::size_type pos = 0;
if ( i < 0 ) {
result = '-';
i = -i;
pos = 1;
}
while ( i > 0 ) {
result.insert( pos, 1, char( '0' + i % 10 ) );
i /= 10;
}
}
return result;
}

string itostr( int i ) {
string result;
itostr( i, result );
return result;
}


Hmm ... Maybe somebody ought to test all these functions and see which
has the best features on grounds of speed, stack/heap used and also
reliability (IOW likelihood of failure or data corruption). Maybe even
the original stringstream wouldnt do too bad then ?

Then it should be not too difficult to write a standardisation proposal
.. I guess it has to be called itostr though!

regards
Andy Little

Mar 12 '06 #32

P: n/a

Daniel T. wrote:
[...]
result += "-2147483648";
}


BTW Thats not portable of course. You might be able to use BOOST
Preprocessor to stringize INT_MIN.:

http://www.boost.org/libs/preprocess...stringize.html

Anyway if that doesnt work I'm sure there would be some way to do it.

regards
Andy Little

Mar 12 '06 #33

P: n/a
On 11 Mar 2006 16:50:04 -0800, an**@servocomm.freeserve.co.uk wrote:
In that case things are much simpler. Now I added a traits class for
the format string so potentially extending the useage to other integer
types, though it seems sprintf is a bit limited to signed and unsigned
int only..whatever...

#include <cstdio>
#include <limits>
#include <string>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_integral.hpp>

....

Ahem, wasn't a simple solution desired?
Mar 12 '06 #34

P: n/a
Roland Pibinger wrote:
Andy Little wrote
#include <cstdio>
#include <limits>
#include <string>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_integral.hpp> ...

Ahem, wasn't a simple solution desired?


I like to use enable_if. It improves (IMO) the error message if I
passed a double rather than a int for example. So it makes my life a
bit simpler. However its not in the C++ standard I guess Try code
below re that ----->

BTW It would also be useful to template param the string char_type then
wrap sprintf/swprintf in a functor and select based on the char_type.
Then the function would be even simpler wouldnt it .... ;-)

regards
Andy Little

-----------------------
#include <cstdio>
#include <limits>
#include <string>

// comment/uncomment to check difference in error messages
#define USE_ENABLE_IF

#ifdef USE_ENABLE_IF
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_integral.hpp>
#endif

template <typename IntegerType>
struct format;

template <>
struct format<int>{
static const char* specifier(){return "%d";}
};
template <>
struct format<unsigned int>{
static const char* specifier(){return "%u";}
};

template <typename IntegerType>
inline
#ifdef USE_ENABLE_IF
typename boost::enable_if<
boost::is_integral<IntegerType>,
std::string&::type

#else
std::string&
#endif
itostr (IntegerType i, std::string& out)
{
std::string::value_type buf[
std::numeric_limits<IntegerType>::digits10 + 3
];
std::string::size_type len
= std::sprintf(buf, format<IntegerType>::specifier(), i);
out.assign(buf,len);
return out;
}

#include <iostream>
int main()
{
std::string str;
itostr(1.,str);
}

regards
Andy Little

Mar 12 '06 #35

P: n/a
On Sun, 12 Mar 2006 03:58:25 GMT, "Daniel T."
<po********@earthlink.net> wrote:
Why put a 128 char buffer on the stack when string already has one
imbedded in it...
because it costs nothing. But I probably change it to
std::string::value_type buf[3 * sizeof(int) + 1];
string& itostr( int i, string& result )
{
result.clear();
this may delete the internal buffer for some string implementations
if ( i == INT_MIN ) {
result += "-2147483648";
}
else if ( i == 0 ) {
result = '0';
}
else {
string::size_type pos = 0;
if ( i < 0 ) {
result = '-';
i = -i;
pos = 1;
}
while ( i > 0 ) {
result.insert( pos, 1, char( '0' + i % 10 ) );
this may cause string reallocations for some string implementations
(IIRC even some professional implementations)
i /= 10;
}
}
return result;
}


With the *printf functions you can format the string output. An
extended version of the above function could offer output format
alternatives to users. Not as format string but in a safe way.

Best wishes,
Roland Pibinger
Mar 12 '06 #36

P: n/a
an**@servocomm.freeserve.co.uk wrote:
Daniel T. wrote:
[...]

result += "-2147483648";
}

BTW Thats not portable of course. You might be able to use BOOST
Preprocessor to stringize INT_MIN.:


You're looking for a string that converts to the minimum representable
value?

#define XSTR(x) #x
#define STR(x) XSTR(x)
STR(INT_MIN)

But note that on some implementations, INT_MIN is defined more like
(-2147483657-1).

--

Pete Becker
Roundhouse Consulting, Ltd.
Mar 12 '06 #37

P: n/a

Pete Becker wrote:
an**@servocomm.freeserve.co.uk wrote:
Daniel T. wrote:
[...]

result += "-2147483648";
}

BTW Thats not portable of course. You might be able to use BOOST
Preprocessor to stringize INT_MIN.:


You're looking for a string that converts to the minimum representable
value?

#define XSTR(x) #x
#define STR(x) XSTR(x)
STR(INT_MIN)

But note that on some implementations, INT_MIN is defined more like
(-2147483657-1).


hmm..IIRC Its you that started us on this rocky road, further up this
thread. Now look where its ended up using nested macros!

OK How about this... just to initalise that value:

#include <sstream>
#include <iostream>
#include <string>

std::string
int_min_init()
{
std::ostringstream s;
s << INT_MIN;
return s.str();
}
std::string const & int_min()
{
static std::string const& str = int_min_init();
return str;
}

// now use
result += int_min();

See .. I can still get an ostringstream in somewhere... :-)

regards
Andy Little

Mar 12 '06 #38

P: n/a
In article <44**************@news.utanet.at>,
rp*****@yahoo.com (Roland Pibinger) wrote:
On Sun, 12 Mar 2006 03:58:25 GMT, "Daniel T."
<po********@earthlink.net> wrote:
Why put a 128 char buffer on the stack when string already has one
imbedded in it...


because it costs nothing. But I probably change it to
std::string::value_type buf[3 * sizeof(int) + 1];
string& itostr( int i, string& result )
{
result.clear();


this may delete the internal buffer for some string implementations


Then change the line to:
result.reserve( numeric_limits<float>::digits10 + 2 );

or some such. But then you have a problem with "result = ..." calls
below because they *may* reduce the size of the internal buffer thus
defeating the reserve call.
if ( i == INT_MIN ) {
result += "-2147483648";
}
else if ( i == 0 ) {
result = '0';
}
else {
string::size_type pos = 0;
if ( i < 0 ) {
result = '-';
i = -i;
pos = 1;
}
while ( i > 0 ) {
result.insert( pos, 1, char( '0' + i % 10 ) );


this may cause string reallocations for some string implementations
(IIRC even some professional implementations)
i /= 10;
}
}
return result;
}


With the *printf functions you can format the string output. An
extended version of the above function could offer output format
alternatives to users. Not as format string but in a safe way.


But then your right back to using something very much like stringstream
which Mr. Becker (and apparently only Mr Becker) finds "too expensive".
--
Magic depends on tradition and belief. It does not welcome observation,
nor does it profit by experiment. On the other hand, science is based
on experience; it is open to correction by observation and experiment.
Mar 12 '06 #39

P: n/a
In article <11*********************@i39g2000cwa.googlegroups. com>,
an**@servocomm.freeserve.co.uk wrote:
Hmm ... Maybe somebody ought to test all these functions and see which
has the best features on grounds of speed, stack/heap used and also
reliability (IOW likelihood of failure or data corruption). Maybe even
the original stringstream wouldnt do too bad then ?

Then it should be not too difficult to write a standardisation proposal
. I guess it has to be called itostr though!


I don't think itostr is a good name. Personally, I like
lexical_cast<Type>. As in:

template < typename T, typename U >
T lexical_cast( const U& u ) {
std::stringstream ss;
T t;
if ( !( ss << u && ss >> t ) ) throw std::bad_cast();
return t;
}

template < >
std::string lexical_cast<std::string>( const int& u ) {
// do whatever you think is "least expensive" here Pete.
}
--
Magic depends on tradition and belief. It does not welcome observation,
nor does it profit by experiment. On the other hand, science is based
on experience; it is open to correction by observation and experiment.
Mar 12 '06 #40

P: n/a
Pete Becker wrote:
#define XSTR(x) #x
#define STR(x) XSTR(x)
STR(INT_MIN)

But note that on some implementations, INT_MIN is defined more like
(-2147483657-1).


.... or as '(~0)'.
--
<mailto:di***********@yahoo.com> <http://www.dietmar-kuehl.de/>
<http://www.eai-systems.com> - Efficient Artificial Intelligence
Mar 12 '06 #41

P: n/a
an**@servocomm.freeserve.co.uk wrote:
Pete Becker wrote:
an**@servocomm.freeserve.co.uk wrote:

BTW Thats not portable of course. You might be able to use BOOST
Preprocessor to stringize INT_MIN.:

You're looking for a string that converts to the minimum representable
value?

#define XSTR(x) #x
#define STR(x) XSTR(x)
STR(INT_MIN)

But note that on some implementations, INT_MIN is defined more like
(-2147483657-1).

hmm..IIRC Its you that started us on this rocky road, further up this
thread. Now look where its ended up using nested macros!


Well, that's a pretty standard idiom. And it's far easier than
installing a preprocessor library just so you don't have to write a
two-line macro.
OK How about this... just to initalise that value:


How about this:

#if INT_MIN == 0xffff
const char *int_min = "0xffff";
#elif INT_MIN == 0xffffffff
const char *int_min = "0xffffffff";
#elif INT_MIN == 0xffffffffffffffff
const char *int_min = "0xffffffffffffffff";
#else
#error Don't know how to initialize int_min
#endif

--

Pete Becker
Roundhouse Consulting, Ltd.
Mar 12 '06 #42

P: n/a
Pete Becker wrote:
How about this:

#if INT_MIN == 0xffff
const char *int_min = "0xffff";
#elif INT_MIN == 0xffffffff
const char *int_min = "0xffffffff";
#elif INT_MIN == 0xffffffffffffffff
const char *int_min = "0xffffffffffffffff";
#else
#error Don't know how to initialize int_min
#endif


Sure, but its pragmatic rather than elegant.

regards
Andy Little

Mar 13 '06 #43

P: n/a
Dietmar Kuehl wrote:
Pete Becker wrote:
#define XSTR(x) #x
#define STR(x) XSTR(x)
STR(INT_MIN)

But note that on some implementations, INT_MIN is defined more like
(-2147483657-1).


... or as '(~0)'.


It occurs though that "technically" the user must be happy with that.
Whatever the output actually is in this case its "technically" correct.
There is no detailed specification for this output after all. Its just
"some representation" of the input , which the above fulfills ... :-)

regards
Andy Little

Mar 13 '06 #44

This discussion thread is closed

Replies have been disabled for this discussion.