4

I'm interested (for various reasons) format using sprintf with the result in a std::string object. The most syntactically direct way I came up with is:

char* buf;
sprintf(buf, ...);
std::string s(buf);

Any other ideas?

Ehtesh Choudhury
  • 7,452
  • 5
  • 42
  • 48
chriskirk
  • 761
  • 1
  • 11
  • 22
  • 4
    Are you aware that your code as is causes a buffer overflow or is this a genuine bug in the code you’re using at the moment? – Konrad Rudolph Jan 05 '12 at 20:24
  • Possible duplicate of [std::string formatting like sprintf](http://stackoverflow.com/questions/2342162/stdstring-formatting-like-sprintf) – 200_success Aug 19 '16 at 17:59

3 Answers3

7

Don't use the printf line of functions for formatting in C++. Use the language feature of streams (stringstreams in this case) which are type safe and don't require the user to provide special format characters.

If you really really want to do that, you could pre-allocate enough space in your string and then resize it down although I'm not sure if that's more efficient than using a temporary char buffer array:

std::string foo;
foo.resize(max_length);
int num_bytes = snprintf(&foo[0], max_length, ...);
if(num_bytes < max_length)
{
    foo.resize(num_bytes);
}
Mark B
  • 95,107
  • 10
  • 109
  • 188
  • 1
    I think I heard once that the elements of `basic_string` are not guaranteed to be contiguous, and so using `&foo[0]` like this would technically be undefined behavior. I also *think* I heard this was changed in C++11, I'm not sure though. – Benjamin Lindley Jan 05 '12 at 20:33
  • 4
    @Benjamin : C++03 proper does not require contiguous storage for `std::basic_string<>`, but [library issue 530](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#530) requires it and every compiler vendor I'm aware of has adhered to this for years. Also, you're correct that C++11 requires it. – ildjarn Jan 05 '12 at 20:37
  • Should `max_length` count the terminating null byte, then? I think I heard once that `basic_string` does not use null-termination. – Hendrik Nov 27 '12 at 12:48
  • The stream interface is not internationalizable. BTW. You can get the length of a string by passing a NULL pointer to snprintf. – Keinstein May 25 '14 at 16:38
1

Answered here. To get length of buffer needed, call:

snprintf( nullptr, 0, format, args... )

You can write short function which can be used as such:

std::string s = string_sprintf("%g, %g\n", 1.23, 0.001);

Example in linked stackoverflow answer.

Community
  • 1
  • 1
user2622016
  • 6,060
  • 3
  • 32
  • 53
1

If you absolutely want to use sprintf, there is no more direct way than the one you wrote.

sprintf Writes into the array pointed by str a C string

If you want to transform this C string into a std::string, there is no better and safer way than the one you wrote.

Xavier V.
  • 6,068
  • 6
  • 30
  • 35
  • 1
    Never advocate `sprintf` when `snprintf` is available on almost every system (assuming C++ streams aren't an option). – Mark B Jan 05 '12 at 20:32