C++ format 格式化字符串实现方式
2018年04月23日 10:18:03 slitaz 阅读数 8088更多
分类专栏: C++11
http://stackoverflow.com/questions/2342162/stdstring-formatting-like-sprintf
You can't do it directly, because you don't have write access to the underlying buffer (until C++11; see Dietrich Epp's comment). You'll have to do it first in a c-string, then copy it into a std::string:
charbuff[100];
snprintf(buff, sizeof(buff),"%s","Hello");
std::stringbuffAsStdStr = 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::stringcopyOfStr = stringStream.str();
https://www.zhihu.com/question/35967887/answer/125238385
boost::format
http://stackoverflow.com/questions/2342162/stdstring-formatting-like-sprintf
Emphasising C++11std::snprintf, this becomes a pretty easyandsafe task. I see a lotofanswersonthis question that were apparently written before the timeofC++11whichusefixed buffer lengthsandvargs, something I wouldnotrecommendforsafety, efficiencyandclarity reasons.
#include <memory>
#include <iostream>
#include
#include <cstdio>
usingnamespacestd;//Don't if you're in a header-file
template<typename ... Args>
stringstring_format(conststd::string& format, Args ... args )
{
size_t size = snprintf( nullptr, 0, format.c_str(), args ... ) + 1; // Extra space for '\0'
unique_ptr buf(new char[ size ] );
snprintf( buf.get(), size, format.c_str(), args ... );
return string( buf.get(), buf.get() + size - 1 ); // We don't want the '\0' inside
}
Line by line explanation:
Aim:Writetoa char* by using std::snprintfandthenconvert thattoa std::string.
First, we determine the desired lengthofthe chararray.
From cppreference.com:
Return value
[...]Ifthe resultingstringgets truncated duetobuf_size limit,functionreturnsthetotalnumberofcharacters(notincluding the terminatingnull-byte)whichwouldhavebeenwritten,ifthelimitwasnotimposed.
Thismeansthatthedesiredsizeisthenumberofcharactersplusone,sothatthenull-terminatorwillsitafterallothercharactersandthatitcanbecutoffbythestringconstructoragain.Thisissuewasexplainedby@alexk7inthecomments.
Then,weallocateanewcharacterarrayandassignittoastd::unique_ptr. Thisisgenerally advised,asyou 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!
After that, we can of course just use snprintf for its intended use and write the formatted string to the char[] and afterwards create and return a new std::string from that.
You can see an example in action here.
Additional information for Visual Studio users:
As explained in this answer, Microsoft renamed std::snprintf to _snprintf (yes, without std::). MS further set it as deprecated and advises to use _snprintf_s instead, however _snprintf_s won't accept the buffertobe zeroorsmaller than the formatted outputandwillnotcalculate the outputs lengthifthat occurs. Soinordertoget ridofthe deprecation warnings during compilation, you can insert the following line at the topofthefilewhich contains theuseof_snprintf:
#pragma warning(disable :4996)
https://github.com/fmtlib/fmt#compile-time-and-code-bloat
fmt is an open-source formatting library for C++. It can be used as a safe alternative to printf or as a fast alternative to IOStreams.
https://github.com/c42f/tinyformat
tinyformat.h is a type safe printf replacement library in a single C++ header file. If you've ever wanted printf("%s", s) to just work regardless of the type of s, tinyformat might be for you. Design goals include:
Type safety and extensibility for user defined types.
C99 printf() compatibility, to the extent possible using std::ostream
Simplicity and minimalism. A single header file to include and distribute with your projects.
Augment rather than replace the standard stream formatting mechanism
C++98 support, with optional C++11 niceties