ugeb
asked on
How to print into std::string like sprintf using C++11?
In the past when I've needed a formatted string, I've created a char buffer and then did sprintf into that buffer. Now that C++ has the std string class, I'd like to use it more, but it doesn't seem to play nice all the time.
I know I can still create the buffer, sprintf into that buffer and then convert to string, but is there a better way? For example, if I have the following (junk code):
int i=1;
int j=4;
char buf[50];
sprintf(buf,"Pair (%d,%d) = %f\n",i,j,(double)i/j);
outputs:
Pair (1,4) = 0.25
How can I print that string directly into a std::string instead of going through a char buffer?
Using: C++11, Visual Studio 2013
I know I can still create the buffer, sprintf into that buffer and then convert to string, but is there a better way? For example, if I have the following (junk code):
int i=1;
int j=4;
char buf[50];
sprintf(buf,"Pair (%d,%d) = %f\n",i,j,(double)i/j);
outputs:
Pair (1,4) = 0.25
How can I print that string directly into a std::string instead of going through a char buffer?
Using: C++11, Visual Studio 2013
Use std: :stringstream.
It is really strange why something like
CStrBuf is not implemented for std::string. I like this helper a lot
CStrBuf is not implemented for std::string. I like this helper a lot
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
So these 2 lines:
char buf[50];
sprintf(buf,"Pair (%d,%d) = %f\n",i,j,(double)i/j);
which are simple and easy to read, turn into this convoluted mess?std::ostringstream oss1, oss2;
oss2 << "Pair (" << i << "," << j << ") = " << std::fixed << std::setprecision(1) << (double(i)/j) << std::endl;
buf = oss2.str();
So I actually LOSE readability and conciseness in moving to std::string? This is an enormous step sideways. I have strings I need to generate with many more parameters and that would just make this code a mess. Sounds like I just need to stick to the character buffer.
>> note, contrary to sprintf the above output statement was checked by the compiler
Would have been nice if you'd mentioned you were building on my answer. http:#41861491
Unfortunately, I was in the car and so unable to give an example.
Nice example, BTW. :)
>> CStrBuf is not implemented for std::string. I like this helper a lot
Because you should use std::stringstream
Would have been nice if you'd mentioned you were building on my answer. http:#41861491
Unfortunately, I was in the car and so unable to give an example.
Nice example, BTW. :)
>> CStrBuf is not implemented for std::string. I like this helper a lot
Because you should use std::stringstream
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
It's also quite readable when formatted properly:
auto && oss = std::ostringstream();
oss
<< "Pair (" << i << "," << j << ") = "
<< std::fixed << std::setprecision(1)
<< (double(i)/j)
<< std::endl;
auto && buf = oss.str();
BTW: If you really wanted to use sprintf...
I don't recommend this, but it's a way of doing what you want and still using std::string.
auto && buf = std::string();
buf.resize(N); // where N is the size of the string buffer you need;
sprintf(&buf[0], "Pair (%d,%d) = %f\n", i, j, (double)i/j);
std::cout << buf << std::endl;
I don't recommend this, but it's a way of doing what you want and still using std::string.
ASKER
@evilrix, with your reformatting it is a little better to read, but I would have to spend much more time interpreting how it would look on execution. And, it takes 3x as long to write it, you have all the "<<" getting in the way.
While the Boost lib is a good idea, it should not be necessary. C++ should, by this point, have far better string functionality built in, especially formatting. While I had occasional issues with printf and sprintf, they are far superior, in my opinion, to streams in terms of readability and development time.
I wish I could stick with Python ...
While the Boost lib is a good idea, it should not be necessary. C++ should, by this point, have far better string functionality built in, especially formatting. While I had occasional issues with printf and sprintf, they are far superior, in my opinion, to streams in terms of readability and development time.
I wish I could stick with Python ...
ASKER
@evilrix,
I like that new solution. It seems like a bit of a kluge, but in this case it might just work well. It seems it would have the same issues as my original code, except I can avoid the char buffer now, correct?
I like that new solution. It seems like a bit of a kluge, but in this case it might just work well. It seems it would have the same issues as my original code, except I can avoid the char buffer now, correct?
>> C++ should, by this point, have far better string functionality built in
It does, stringstream. It's like anything, it takes a little time to get used to it; however, it is better. Like I said, not only is it compile time safe (unlike sprintf), it is designed to be extensible so that you can stream your own objects. Yes, it's more verbose, but verbose doesn't mean it's not better. Trust me when I say that using sprintf really isn't the way to go. Whilst it may seem better (because it's what you are used to), it's really not. It's a dangerous function that is the cause of many hard to uncover code defects. Specifically, it can lead to exploits in code that you just can get with stringstream.
I do agree that stringstream does take some getting used to, but you can do something like this that you couldn't do with sprintf...
auto && s = oss.str();
std::out << s << std::endl;
It does, stringstream. It's like anything, it takes a little time to get used to it; however, it is better. Like I said, not only is it compile time safe (unlike sprintf), it is designed to be extensible so that you can stream your own objects. Yes, it's more verbose, but verbose doesn't mean it's not better. Trust me when I say that using sprintf really isn't the way to go. Whilst it may seem better (because it's what you are used to), it's really not. It's a dangerous function that is the cause of many hard to uncover code defects. Specifically, it can lead to exploits in code that you just can get with stringstream.
I do agree that stringstream does take some getting used to, but you can do something like this that you couldn't do with sprintf...
struct mypair
{
int x;
int y;
};
ostream operator << (ostream & out, mypair const & pair)
{
oss
<< "Pair (" <<pair.x << "," << pair.y << ") = "
<< std::fixed << std::setprecision(1)
<< (double(pair.x)/pair.y);
}
auto && oss = std::ostringstream();
auto && pair = mypair{1, 2};
oss << pair << std::endl;
pair.x = 2;
pair.y = 4;
oss << pair << std::endl;
auto && s = oss.str();
std::out << s << std::endl;
Unfortunately, I was in the car and so unable to give an example.sorry, actually i waited some time for you to give a sample yourself.
[quoteAnd, it takes 3x as long to write it, you have all the "<<" getting in the way.
[/quote]
you were comparing
sprintf(buf,"Pair (%d,%d) = %f\n",i,j,(double)i/j);
with code
oss1 << "Pair (" << i << "," << j << ") = " << (double(i)/j) << "\n";
and said the second is a mess and less readable. your code has 50 characters, the other code has 54 (spaces outside of literals not counted). the first is good readable for the author if you only look for the formatting and not for the final output. after a few months you will need some time to find out which format specifier belongs to which argument. the second can be read from left to right and with a few efforts you could have (as shown by evilrix)
oss1 << Pair(i, j) << "\n";
if you add the following to a header file
#define STREAM(s) (((std::ostringstream&)(std::ostringstream() << s)).str())
you can do like
std::string s = STREAM(i << "/" << j << " = " << (1.*i)/j);
or
if (ret != 0)
{
std::cerr << STREAM("Error " << ret << ", in SomeFunction(" << arg1 << ", " << arg2 << ")\n");
}
do you still think it is a mess?
Sara