views:

469

answers:

6

Hi guys, I have to format std::string with sprintf and send it into file stream. How can I do this?

+6  A: 

You can't do it directly, because you don't have write access to the underlying buffer. You'll have to do it first in a c-string, then copy it into a std::string:

  char buff[100];
  sprintf(buff, "%s", "Hello");
  std::string buffAsStdStr = buff;

But I'm not sure why you wouldn't just use a string stream? I'm assuming you have specific reasons to not just do this:

  std::ostringstream stringStream;
  stringStream << "Hello";
  std::string copyOfStr = stringStream.str();
Doug T.
+1 This looks very vaible
Hazior
how to format with ostringstream?
Ockonal
He has not mentioned it ... follow the link in my post :D
Hassan Syed
The magic cookie in `char buf[100];` makes this solution not very robust. But the essential idea is there.
John Dibling
Better use `snprintf` than `sprintf`.
KennyTM
Ban `sprintf`. Seriously, surgically remove it from your libraries if you have to. Same with `strcpy`.
Mike DeSimone
Why even use snprintf when C++ stringstreams does formatting? sure if you need performance snprintf is better.
Hassan Syed
@Hassan: Some people hate streams. Myself included.
John Dibling
@john out of interest, for what reasons ?
Hassan Syed
@Hassan: Well, I could give you a bunch of reasons. One, streams are slow. Two, many implementations I have used are buggy as all get out. Three, I find it much easier in fact quite the opposite. Just answering your question
John Dibling
+3  A: 

string doesn't have what you need, but std::stringstream does. Use a stringstream to create the string and then extract the string. Here is a comprehensive list on the things you can do. For example:

cout.setprecision(10); //stringstream is a stream like cout

will give you 10 decimal places of precision when printing a double or float.

Hassan Syed
+4  A: 

If you only want a printf-like syntax (without calling printf yourself), have a look at Boost Format.

Timo Geusch
+10  A: 

If you want to use a format string, try Boost.Format.

KennyTM
boost is to big for my project.
Ockonal
@Ockonal: Why? How is it "too big"? `Boost.Format` is a header-only library. It doesn't get much smaller than that.
jalf
you can prune the libraries you need out of boost as well. Using a suplied tool.
Hassan Syed
A: 
std::string str(100, ' ');
sprintf(&str[0], "%s %s", "Hello", "World");
Sean
Very dangerous to use this technique.
William Brendel
Yep, you're setting yourself up for a potential buffer overrun.
Joe Gauterin
This is not guaranteed by the standard. Even if most implementations do hold the internal contents in a contiguous buffer, that is not a requirement in the standard, that does in fact mention that a possible implementation of a string would be using 'ropes' (uncontiguous blocks of memory) so even if you check that the string size is enough to hold the contents of the snprintf, there is no guarantee that the call will not kill the application.
David Rodríguez - dribeas
Well, I stand corrected then. I'd love to know how the c_str and data methods could possibly be implemented on top of noncontiguous memory, though.
Sean
c_str() and data() are defined as returning a const pointer, which is valid only until the string changes. That's the giveaway: they may return a copy.
MSalters
A: 

A very late answer, but for those who, like me, do like the 'sprintf'-way: I've written and are using the following functions. If you like it, you can expand the %-options to more closely fit the sprintf ones; the ones in there currently are sufficient for my needs. You use stringf() and stringfappend() same as you would sprintf. Just remember that the parameters for ... must be POD types.

//=============================================================================
void DoFormatting(string& sF, const char* sformat, va_list marker)
{
    char *s, c, ch=0;
    int n, i=0, m;
    long l;
    float f;
    double d;
    string sf = sformat;
    stringstream ss;

    m = sf.length();
    while (i<m)
    {
        ch = sf.at(i);
        if (ch == '%')
        {
            i++;
            if (i<m) 
            {
                ch = sf.at(i);
                switch(ch)
                {
                    case 's': { s = va_arg(marker, char*);  ss << s;         } break;
                    case 'c': { n = va_arg(marker, int);    ss << (char)n;   } break;
                    case 'd': { n = va_arg(marker, int);    ss << (int)n;    } break;
                    case 'l': { l = va_arg(marker, long);   ss << (long)l;   } break;
                    case 'f': { d = va_arg(marker, double); ss << (float)d;  } break;
                    case 'e': { d = va_arg(marker, double); ss << (double)d; } break;
                    case '%': { ss << '%'; } break;
                    default: 
                    {
                        ss << "%" << ch << " <- unknown format ";
                        i = m; //get out of loop
                    }
                }
            }
        }
        else ss << ch;
        i++;
    }
    va_end(marker);             
    sF = ss.str();
}

//=============================================================================
void stringf(string& stgt,const char *sformat, ... )
{
    va_list marker;
    va_start(marker, sformat);
    DoFormatting(stgt, sformat, marker);
}

//=============================================================================
void stringfappend(string& stgt,const char *sformat, ... )
{
    string sF = "";
    va_list marker;
    va_start(marker, sformat);
    DoFormatting(sF, sformat, marker);
    stgt += sF;
}
slashmais