I have to format std::string
with sprintf
and send it into file stream. How can I do this?
C++ – std::string Formatting Like sprintf
c++formattingstdstdstringstring
c++formattingstdstdstringstring
I have to format std::string
with sprintf
and send it into file stream. How can I do this?
Best Answer
Modern C++ makes this super simple.
C++20
C++20 introduces
std::format
, which allows you to do exactly that. It uses replacement fields similar to those in python:Code from cppreference.com, CCÂ BY-SA and GFDL
Check out the compiler support page to see if it's available in your standard library implementation.
As of 2023-07-18, partial support is available starting from:
In all other cases, you can resort to the C++11 solution below, or use the
{fmt}
library, which has the same semantics asstd::format
.C++11
With C++11s
std::snprintf
, this already became a pretty easy and safe task.The code snippet above is licensed under CC0 1.0.
Line by line explanation:
Aim: Write to a
char*
by usingstd::snprintf
and then convert that to astd::string
.First, we determine the desired length of the char array using a special condition in
snprintf
. From cppreference.com:This means that the desired size is the number of characters plus one, so that the null-terminator will sit after all other characters and that it can be cut off by the string constructor again. This issue was explained by @alexk7 in the comments.
snprintf
will return a negative number if an error occurred, so we then check whether the formatting worked as desired. Not doing this could lead to silent errors or the allocation of a huge buffer, as pointed out by @ead in the comments.Because we know that
size_s
can't be negative, we use a static cast to convert it from a signedint
to an unsignedsize_t
. This way, even the most pedantic compiler won't complain about the conversions that would otherwise happen on the next lines.Next, we allocate a new character array and assign it to a
std::unique_ptr
. This is generally advised, as you won't have to manually delete it again.Note that this is not a safe way to allocate a
unique_ptr
with user-defined types as you can not deallocate the memory if the constructor throws an exception!In C++14, you could instead use
make_unique
, which is safe for user-defined types.After that, we can of course just use
snprintf
for its intended use and write the formatted string to thechar[]
.Finally, we create and return a new
std::string
from that, making sure to omit the null-terminator at the end.You can see an example in action here.
If you also want to use
std::string
in the argument list, take a look at this gist.Additional information for Visual Studio users:
As explained in this answer, Microsoft renamed
std::snprintf
to_snprintf
(yes, withoutstd::
). MS further set it as deprecated and advises to use_snprintf_s
instead, however_snprintf_s
won't accept the buffer to be zero or smaller than the formatted output and will not calculate the outputs length if that occurs. So in order to get rid of the deprecation warnings during compilation, you can insert the following line at the top of the file which contains the use of_snprintf
:Final thoughts
A lot of answers to this question were written before the time of C++11 and use fixed buffer lengths or vargs. Unless you're stuck with old versions of C++, I wouldn't recommend using those solutions. Ideally, go the C++20 way.
Because the C++11 solution in this answer uses templates, it can generate quite a bit of code if it is used a lot. However, unless you're developing for an environment with very limited space for binaries, this won't be a problem and is still a vast improvement over the other solutions in both clarity and security.
If space efficiency is super important, these two solution with vargs and vsnprintf can be useful. DO NOT USE any solutions with fixed buffer lengths, that is just asking for trouble.