Related
From what I have read, this function should work, but for the life of me, I cannot figure out why it isn't.
I override the invalid parameter handler so I can continue running if an invalid parameter is passed (such as a buffer that is too small).
asprintf_s macro takes the parameters of a standard sprintf_s, adds the filename and line number, then calls asprintf_s2. It checks to see if the result would have overflowed the buffer, prints the filename and the line of where the overflowed occurred.
Problem: I'm guessing I'm doing something wrong with the variadic parameters as it always returns an overflow.
Output of program below
#include "stdafx.h"
#include <iostream>
#include <stdio.h>
#include <string>
#include <excpt.h>
#include <stdarg.h>
#define asprintf_s(...) asprintf_s2( __FILE__, __LINE__, __VA_ARGS__)
//#define asprintf_s(...) sprintf_s( __VA_ARGS__ )
inline int asprintf_s2(char *file, int line, char *dest, int sizeOfDest, char *Format, ...)
{
va_list pArgs;
va_start(pArgs, Format);
int sizeOfBuffer = sprintf_s(dest, sizeOfDest, Format, pArgs);
if (sizeOfBuffer == -1) printf("Buffer Overflow! File: %s LINE: %d\n", file, line );
va_end(pArgs);
return sizeOfBuffer;
}
void in_house_invalid_parameter(
const wchar_t * expression,
const wchar_t * function,
const wchar_t * file,
unsigned int line,
uintptr_t pReserved
)
{
// Do nothing on invalid parameter
}
int main()
{
char temp1[3];
char temp80[80];
std::string input;
int k = -3;
_set_invalid_parameter_handler(in_house_invalid_parameter);
strcpy_s(temp1, sizeof(temp1), "XX");
strcpy_s(temp80, sizeof(temp80), "1");
printf("Temp1:'%s'\n", temp1);
k = asprintf_s(temp1, sizeof(temp1), "%s\n", temp80);
printf("k:%d temp1:'%s', temp80:'%s'\n", k, temp1, temp80);
std::getline(std::cin, input);
return 0;
}
You just have to use vsprintf or vsprintf_s function
Edit: or vasprintf for your case
I have to format std::string with sprintf and send it into file stream. How can I do this?
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:
#include <iostream>
#include <format>
int main() {
std::cout << std::format("Hello {}!\n", "world");
}
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 2021-11-28, partial support is available in Visual Studio 2019 16.10, which was released on 2021-05-25 and Clang 14, which is tracked here. In all other cases, you can resort to the C++11 solution below, or use the {fmt} library, which has the same semantics as std::format.
C++11
With C++11s std::snprintf, this already became a pretty easy and safe task.
#include <memory>
#include <string>
#include <stdexcept>
template<typename ... Args>
std::string string_format( const std::string& format, Args ... args )
{
int size_s = std::snprintf( nullptr, 0, format.c_str(), args ... ) + 1; // Extra space for '\0'
if( size_s <= 0 ){ throw std::runtime_error( "Error during formatting." ); }
auto size = static_cast<size_t>( size_s );
std::unique_ptr<char[]> buf( new char[ size ] );
std::snprintf( buf.get(), size, format.c_str(), args ... );
return std::string( buf.get(), buf.get() + size - 1 ); // We don't want the '\0' inside
}
The code snippet above is licensed under CC0 1.0.
Line by line explanation:
Aim: Write to a char* by using std::snprintf and then convert that to a std::string.
First, we determine the desired length of the char array using a special condition in snprintf. From cppreference.com:
Return value
[...] If the resulting string gets truncated due to buf_size limit,
function returns the total number of characters (not including the
terminating null-byte) which would have been written, if the limit was
not imposed.
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.
int size_s = std::snprintf( nullptr, 0, format.c_str(), args ... ) + 1;
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.
if( size_s <= 0 ){ throw std::runtime_error( "Error during formatting." ); }
Because we know that size_s can't be negative, we use a static cast to convert it from a signed int to an unsigned size_t. This way, even the most pedantic compiler won't complain about the conversions that would otherwise happen on the next lines.
size_t size = static_cast<size_t>( size_s );
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!
std::unique_ptr<char[]> buf( new char[ size ] );
In C++14, you could instead use make_unique, which is safe for user-defined types.
auto buf = std::make_unique<char[]>( size );
After that, we can of course just use snprintf for its intended use and write the formatted string to the char[].
std::snprintf( buf.get(), size, format.c_str(), args ... );
Finally, we create and return a new std::string from that, making sure to omit the null-terminator at the end.
return std::string( buf.get(), buf.get() + size - 1 );
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, without std::). 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:
#pragma warning(disable : 4996)
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.
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:
char buff[100];
snprintf(buff, sizeof(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();
C++11 solution that uses vsnprintf() internally:
#include <stdarg.h> // For va_start, etc.
std::string string_format(const std::string fmt, ...) {
int size = ((int)fmt.size()) * 2 + 50; // Use a rubric appropriate for your code
std::string str;
va_list ap;
while (1) { // Maximum two passes on a POSIX system...
str.resize(size);
va_start(ap, fmt);
int n = vsnprintf((char *)str.data(), size, fmt.c_str(), ap);
va_end(ap);
if (n > -1 && n < size) { // Everything worked
str.resize(n);
return str;
}
if (n > -1) // Needed size returned
size = n + 1; // For null char
else
size *= 2; // Guess at a larger size (OS specific)
}
return str;
}
A safer and more efficient (I tested it, and it is faster) approach:
#include <stdarg.h> // For va_start, etc.
#include <memory> // For std::unique_ptr
std::string string_format(const std::string fmt_str, ...) {
int final_n, n = ((int)fmt_str.size()) * 2; /* Reserve two times as much as the length of the fmt_str */
std::unique_ptr<char[]> formatted;
va_list ap;
while(1) {
formatted.reset(new char[n]); /* Wrap the plain char array into the unique_ptr */
strcpy(&formatted[0], fmt_str.c_str());
va_start(ap, fmt_str);
final_n = vsnprintf(&formatted[0], n, fmt_str.c_str(), ap);
va_end(ap);
if (final_n < 0 || final_n >= n)
n += abs(final_n - n + 1);
else
break;
}
return std::string(formatted.get());
}
The fmt_str is passed by value to conform with the requirements of va_start.
NOTE: The "safer" and "faster" version doesn't work on some systems. Hence both are still listed. Also, "faster" depends entirely on the preallocation step being correct, otherwise the strcpy renders it slower.
boost::format() provides the functionality you want:
As from the Boost format libraries synopsis:
A format object is constructed from a format-string, and is then given arguments through repeated calls to operator%.
Each of those arguments are then converted to strings, who are in turn combined into one string, according to the format-string.
#include <boost/format.hpp>
cout << boost::format("writing %1%, x=%2% : %3%-th try") % "toto" % 40.23 % 50;
// prints "writing toto, x=40.230 : 50-th try"
C++20 has std::format which resembles sprintf in terms of API but is fully type-safe, works with user-defined types, and uses Python-like format string syntax. Here's how you will be able to format std::string and write it to a stream:
std::string s = "foo";
std::cout << std::format("Look, a string: {}", s);
Alternatively, you could use the {fmt} library to format a string and write it to stdout or a file stream in one go:
fmt::print("Look, a string: {}", s);
As for sprintf or most of the other answers here, unfortunately they use varargs and are inherently unsafe unless you use something like GCC's format attribute which only works with literal format strings. You can see why these functions are unsafe on the following example:
std::string format_str = "%s";
string_format(format_str, format_str[0]);
where string_format is an implementation from the Erik Aronesty's answer. This code compiles, but it will most likely crash when you try to run it:
$ g++ -Wall -Wextra -pedantic test.cc
$ ./a.out
Segmentation fault: 11
Disclaimer: I'm the author of {fmt} and C++20 std::format.
I wrote my own using vsnprintf so it returns string instead of having to create my own buffer.
#include <string>
#include <cstdarg>
//missing string printf
//this is safe and convenient but not exactly efficient
inline std::string format(const char* fmt, ...){
int size = 512;
char* buffer = 0;
buffer = new char[size];
va_list vl;
va_start(vl, fmt);
int nsize = vsnprintf(buffer, size, fmt, vl);
if(size<=nsize){ //fail delete buffer and try again
delete[] buffer;
buffer = 0;
buffer = new char[nsize+1]; //+1 for /0
nsize = vsnprintf(buffer, size, fmt, vl);
}
std::string ret(buffer);
va_end(vl);
delete[] buffer;
return ret;
}
So you can use it like
std::string mystr = format("%s %d %10.5f", "omg", 1, 10.5);
Tested, Production Quality Answer
This answer handles the general case with standards compliant techniques. The same approach is given as an example on CppReference.com near the bottom of their page. Unlike their example, this code fits the question's requirements and is field tested in robotics and satellite applications. It also has improved commenting. Design quality is discussed further below.
#include <string>
#include <cstdarg>
#include <vector>
// requires at least C++11
const std::string vformat(const char * const zcFormat, ...) {
// initialize use of the variable argument array
va_list vaArgs;
va_start(vaArgs, zcFormat);
// reliably acquire the size
// from a copy of the variable argument array
// and a functionally reliable call to mock the formatting
va_list vaArgsCopy;
va_copy(vaArgsCopy, vaArgs);
const int iLen = std::vsnprintf(NULL, 0, zcFormat, vaArgsCopy);
va_end(vaArgsCopy);
// return a formatted string without risking memory mismanagement
// and without assuming any compiler or platform specific behavior
std::vector<char> zc(iLen + 1);
std::vsnprintf(zc.data(), zc.size(), zcFormat, vaArgs);
va_end(vaArgs);
return std::string(zc.data(), iLen); }
#include <ctime>
#include <iostream>
#include <iomanip>
// demonstration of use
int main() {
std::time_t t = std::time(nullptr);
std::cerr
<< std::put_time(std::localtime(& t), "%D %T")
<< " [debug]: "
<< vformat("Int 1 is %d, Int 2 is %d, Int 3 is %d", 11, 22, 33)
<< std::endl;
return 0; }
Predictable Linear Efficiency
Two passes are necessities for a secure, reliable, and predictable reusable function per the question specifications. Presumptions about the distribution of sizes of vargs in a reusable function is bad programming style and should be avoided. In this case, arbitrarily large variable length representations of vargs is a key factor in choice of algorithm.
Retrying upon overflow is exponentially inefficient, which is another reason discussed when the C++11 standards committee discussed the above proposal to provide a dry run when the write buffer is null.
In the above production ready implementation, the first run is such a dry run to determine allocation size. No allocation occurs. Parsing of printf directives and the reading of vargs has been made extremely efficient over decades. Reusable code should be predictable, even if a small inefficiency for trivial cases must be sacrificed.
Security and Reliability
Andrew Koenig said to a small group of us after his lecture at a Cambridge event, "User functions shouldn't rely on the exploitation of a failure for unexceptional functionality." As usual, his wisdom has been shown true in the record since. Fixed and closed security bug issues often indicate retry hacks in the description of the hole exploited prior to the fix.
This is mentioned in the formal standards revision proposal for the null buffer feature in Alternative to sprintf, C9X Revision Proposal, ISO IEC Document WG14 N645/X3J11 96-008. An arbitrarily long string inserted per print directive, "%s," within the constraints of dynamic memory availability, is not an exception, and should not be exploited to produce, "Unexceptional functionality."
Consider the proposal along side the example code given at the bottom of the C++Reference.org page linked to in the first paragraph of this answer.
Also, the testing of failure cases is rarely as robust of success cases.
Portability
All major O.S. vendors provide compilers that fully support std::vsnprintf as part of the c++11 standards. Hosts running products of vendors that no longer maintain distributions should be furnished with g++ or clang++ for many reasons.
Stack Use
Stack use in the 1st call to std::vsnprintf will be less than or equal to that of the 2nd, and and it will be freed before the 2nd call begins. If the first call exceeds stack availability, then std::fprintf would fail too.
In order to format std::string in a 'sprintf' manner, call snprintf (arguments nullptr and 0) to get length of buffer needed. Write your function using C++11 variadic template like this:
#include <cstdio>
#include <string>
#include <cassert>
template< typename... Args >
std::string string_sprintf( const char* format, Args... args ) {
int length = std::snprintf( nullptr, 0, format, args... );
assert( length >= 0 );
char* buf = new char[length + 1];
std::snprintf( buf, length + 1, format, args... );
std::string str( buf );
delete[] buf;
return str;
}
Compile with C++11 support, for example in GCC: g++ -std=c++11
Usage:
std::cout << string_sprintf("%g, %g\n", 1.23, 0.001);
If you only want a printf-like syntax (without calling printf yourself), have a look at Boost Format.
C++20 std::format
It has arrived! The feature is described at: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0645r9.html and uses a Python-like .format() syntax.
I expect that the usage will be like:
#include <format>
#include <string>
int main() {
std::string message = std::format("The answer is {}.", 42);
}
GCC 9.1.0 with g++-9 -std=c++2a still doesn't support it.
The existing fmt library implements it for before it gets official support: https://github.com/fmtlib/fmt as previously mentioned at: std::string formatting like sprintf Install on Ubuntu 22.04:
sudo apt install libfmt-dev
Modify source to replace:
<format> with <fmt/core.h>
std::format to fmt::format
main.cpp
#include <string>
#include <iostream>
#include <fmt/core.h>
int main() {
std::string message = fmt::format("The answer is {}.", 42);
std::cout << message << std::endl;
}
and compile and run with:
g++ -std=c++11 -o main.out main.cpp -lfmt
./main.out
Output:
The answer is 42.
The API will add a new std::format header:
The proposed formatting API is defined in the new header <format> and should have no impact on existing code.
Hexadecimal format {:x}
C++ cout hex values?
Leading zeroes {:03}
Print leading zeros with C++ output operator?
Alignment left {:<}, right {:>}, center {:^}
C++ alignment when printing cout <<
Floating point precision {:.2}
How do I print a double value with full precision using cout?
Set back default floating point print precision in C++
Show sign on positive numbers {:+}
How to print positive numbers with a prefix + in C++
Show booleans as true and false: {:}
Converting bool to text in C++
[edit: 20/05/25] better still...:
In header:
// `say` prints the values
// `says` returns a string instead of printing
// `sayss` appends the values to it's first argument instead of printing
// `sayerr` prints the values and returns `false` (useful for return statement fail-report)<br/>
void PRINTSTRING(const std::string &s); //cater for GUI, terminal, whatever..
template<typename...P> void say(P...p) { std::string r{}; std::stringstream ss(""); (ss<<...<<p); r=ss.str(); PRINTSTRING(r); }
template<typename...P> std::string says(P...p) { std::string r{}; std::stringstream ss(""); (ss<<...<<p); r=ss.str(); return r; }
template<typename...P> void sayss(std::string &s, P...p) { std::string r{}; std::stringstream ss(""); (ss<<...<<p); r=ss.str(); s+=r; } //APPENDS! to s!
template<typename...P> bool sayerr(P...p) { std::string r{}; std::stringstream ss("ERROR: "); (ss<<...<<p); r=ss.str(); PRINTSTRING(r); return false; }
The PRINTSTRING(r)-function is to cater for GUI or terminal or any special output needs using #ifdef _some_flag_, the default is:
void PRINTSTRING(const std::string &s) { std::cout << s << std::flush; }
[edit '17/8/31] Adding a variadic templated version 'vtspf(..)':
template<typename T> const std::string type_to_string(const T &v)
{
std::ostringstream ss;
ss << v;
return ss.str();
};
template<typename T> const T string_to_type(const std::string &str)
{
std::istringstream ss(str);
T ret;
ss >> ret;
return ret;
};
template<typename...P> void vtspf_priv(std::string &s) {}
template<typename H, typename...P> void vtspf_priv(std::string &s, H h, P...p)
{
s+=type_to_string(h);
vtspf_priv(s, p...);
}
template<typename...P> std::string temp_vtspf(P...p)
{
std::string s("");
vtspf_priv(s, p...);
return s;
}
which is effectively a comma-delimited version (instead) of the sometimes hindering <<-operators, used like this:
char chSpace=' ';
double pi=3.1415;
std::string sWorld="World", str_var;
str_var = vtspf("Hello", ',', chSpace, sWorld, ", pi=", pi);
[edit] Adapted to make use of the technique in Erik Aronesty's answer (above):
#include <string>
#include <cstdarg>
#include <cstdio>
//=============================================================================
void spf(std::string &s, const std::string fmt, ...)
{
int n, size=100;
bool b=false;
va_list marker;
while (!b)
{
s.resize(size);
va_start(marker, fmt);
n = vsnprintf((char*)s.c_str(), size, fmt.c_str(), marker);
va_end(marker);
if ((n>0) && ((b=(n<size))==true)) s.resize(n); else size*=2;
}
}
//=============================================================================
void spfa(std::string &s, const std::string fmt, ...)
{
std::string ss;
int n, size=100;
bool b=false;
va_list marker;
while (!b)
{
ss.resize(size);
va_start(marker, fmt);
n = vsnprintf((char*)ss.c_str(), size, fmt.c_str(), marker);
va_end(marker);
if ((n>0) && ((b=(n<size))==true)) ss.resize(n); else size*=2;
}
s += ss;
}
[previous answer]
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(std::string& sF, const char* sformat, va_list marker)
{
char *s, ch=0;
int n, i=0, m;
long l;
double d;
std::string sf = sformat;
std::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 'X':
case 'x':
{
if (++i<m)
{
ss << std::hex << std::setiosflags (std::ios_base::showbase);
if (ch == 'X') ss << std::setiosflags (std::ios_base::uppercase);
char ch2 = sf.at(i);
if (ch2 == 'c') { n = va_arg(marker, int); ss << std::hex << (char)n; }
else if (ch2 == 'd') { n = va_arg(marker, int); ss << std::hex << (int)n; }
else if (ch2 == 'l') { l = va_arg(marker, long); ss << std::hex << (long)l; }
else ss << '%' << ch << ch2;
ss << std::resetiosflags (std::ios_base::showbase | std::ios_base::uppercase) << std::dec;
}
} break;
case '%': { ss << '%'; } break;
default:
{
ss << "%" << ch;
//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;
}
template<typename... Args>
std::string string_format(const char* fmt, Args... args)
{
size_t size = snprintf(nullptr, 0, fmt, args...);
std::string buf;
buf.reserve(size + 1);
buf.resize(size);
snprintf(&buf[0], size + 1, fmt, args...);
return buf;
}
Using C99 snprintf and C++11
This is how google does it: StringPrintf (BSD License)
and facebook does it in a quite similar fashion: StringPrintf (Apache License)
Both provide with a convenient StringAppendF too.
My two cents on this very popular question.
To quote the manpage of printf-like functions:
Upon successful return, these functions return the number of characters printed (excluding the null byte used to end output to strings).
The functions snprintf() and vsnprintf() do not write more than size bytes (including the terminating null byte ('\0')). If the output was truncated due to this limit then the return value is the number of characters (excluding the terminating null byte) which would have been written to the final string if enough space had been available. Thus, a return value of size or more means that the output was truncated.
In other words, a sane C++11 implementation should be the following:
#include <string>
#include <cstdio>
template <typename... Ts>
std::string fmt (const std::string &fmt, Ts... vs)
{
char b;
size_t required = std::snprintf(&b, 0, fmt.c_str(), vs...) + 1;
// See comments: the +1 is necessary, while the first parameter
// can also be set to nullptr
char bytes[required];
std::snprintf(bytes, required, fmt.c_str(), vs...);
return std::string(bytes);
}
It works quite well :)
Variadic templates are supported only in C++11. The answer from pixelpoint show a similar technique using older programming styles.
It's weird that C++ does not have such a thing out of the box. They recently added to_string(), which in my opinion is a great step forward. I'm wondering if they will add a .format operator to the std::string eventually...
Edit
As alexk7 pointed out, A +1 is needed on the return value of std::snprintf, since we need to have space for the \0 byte. Intuitively, on most architectures missing the +1 will cause the required integer to be partially overwritten with a 0. This will happen after the evaluation of required as actual parameter for std::snprintf, so the effect should not be visible.
This problem could however change, for instance with compiler optimization: what if the compiler decides to use a register for the required variable? This is the kind of errors which sometimes result in security issues.
If you are on a system that has asprintf(3), you can easily wrap it:
#include <iostream>
#include <cstdarg>
#include <cstdio>
std::string format(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
std::string format(const char *fmt, ...)
{
std::string result;
va_list ap;
va_start(ap, fmt);
char *tmp = 0;
int res = vasprintf(&tmp, fmt, ap);
va_end(ap);
if (res != -1) {
result = tmp;
free(tmp);
} else {
// The vasprintf call failed, either do nothing and
// fall through (will return empty string) or
// throw an exception, if your code uses those
}
return result;
}
int main(int argc, char *argv[]) {
std::string username = "you";
std::cout << format("Hello %s! %d", username.c_str(), 123) << std::endl;
return 0;
}
Based on the answer provided by Erik Aronesty:
std::string string_format(const std::string &fmt, ...) {
std::vector<char> str(100,'\0');
va_list ap;
while (1) {
va_start(ap, fmt);
auto n = vsnprintf(str.data(), str.size(), fmt.c_str(), ap);
va_end(ap);
if ((n > -1) && (size_t(n) < str.size())) {
return str.data();
}
if (n > -1)
str.resize( n + 1 );
else
str.resize( str.size() * 2);
}
return str.data();
}
This avoids the need to cast away const from the result of .c_str() which was in the original answer.
inline void format(string& a_string, const char* fmt, ...)
{
va_list vl;
va_start(vl, fmt);
int size = _vscprintf( fmt, vl );
a_string.resize( ++size );
vsnprintf_s((char*)a_string.data(), size, _TRUNCATE, fmt, vl);
va_end(vl);
}
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.
You could try this:
string str;
str.resize( _MAX_PATH );
sprintf( &str[0], "%s %s", "hello", "world" );
// optionals
// sprintf_s( &str[0], str.length(), "%s %s", "hello", "world" ); // Microsoft
// #include <stdio.h>
// snprintf( &str[0], str.length(), "%s %s", "hello", "world" ); // c++11
str.resize( strlen( str.data() ) + 1 );
I usually use this:
std::string myformat(const char *const fmt, ...)
{
char *buffer = NULL;
va_list ap;
va_start(ap, fmt);
(void)vasprintf(&buffer, fmt, ap);
va_end(ap);
std::string result = buffer;
free(buffer);
return result;
}
Disadvantage: not all systems support vasprint
This is the code I use to do this in my program... It's nothing fancy, but it does the trick... Note, you will have to adjust your size as applicable. MAX_BUFFER for me is 1024.
std::string Format ( const char *fmt, ... )
{
char textString[MAX_BUFFER*5] = {'\0'};
// -- Empty the buffer properly to ensure no leaks.
memset(textString, '\0', sizeof(textString));
va_list args;
va_start ( args, fmt );
vsnprintf ( textString, MAX_BUFFER*5, fmt, args );
va_end ( args );
std::string retStr = textString;
return retStr;
}
Took the idea from Dacav and pixelpoint's answer. I played around a bit and got this:
#include <cstdarg>
#include <cstdio>
#include <string>
std::string format(const char* fmt, ...)
{
va_list vl;
va_start(vl, fmt);
int size = vsnprintf(0, 0, fmt, vl) + sizeof('\0');
va_end(vl);
char buffer[size];
va_start(vl, fmt);
size = vsnprintf(buffer, size, fmt, vl);
va_end(vl);
return std::string(buffer, size);
}
With sane programming practice I believe the code should be enough, however I'm still open to more secure alternatives that are still simple enough and would not require C++11.
And here's another version that makes use of an initial buffer to prevent second call to vsnprintf() when initial buffer is already enough.
std::string format(const char* fmt, ...)
{
va_list vl;
int size;
enum { INITIAL_BUFFER_SIZE = 512 };
{
char buffer[INITIAL_BUFFER_SIZE];
va_start(vl, fmt);
size = vsnprintf(buffer, INITIAL_BUFFER_SIZE, fmt, vl);
va_end(vl);
if (size < INITIAL_BUFFER_SIZE)
return std::string(buffer, size);
}
size += sizeof('\0');
char buffer[size];
va_start(vl, fmt);
size = vsnprintf(buffer, size, fmt, vl);
va_end(vl);
return std::string(buffer, size);
}
(It turns out that this version is just similar to Piti Ongmongkolkul's answer, only that it doesn't use new and delete[], and also specifies a size when creating std::string.
The idea here of not using new and delete[] is to imply usage of the stack over the heap since it doesn't need to call allocation and deallocation functions, however if not properly used, it could be dangerous to buffer overflows in some (perhaps old, or perhaps just vulnerable) systems. If this is a concern, I highly suggest using new and delete[] instead. Note that the only concern here is about the allocations as vsnprintf() is already called with limits, so specifying a limit based on the size allocated on the second buffer would also prevent those.)
All the answers so far here seems to have one or more of these problems: (1) it may not work on VC++ (2) it requires additional dependencies like boost or fmt (3) its too complicated custom implementation and probably not tested well.
Below code addresses all of above issues.
#include <string>
#include <cstdarg>
#include <memory>
std::string stringf(const char* format, ...)
{
va_list args;
va_start(args, format);
#ifndef _MSC_VER
//GCC generates warning for valid use of snprintf to get
//size of result string. We suppress warning with below macro.
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
#endif
size_t size = std::snprintf(nullptr, 0, format, args) + 1; // Extra space for '\0'
#ifdef __GNUC__
# pragma GCC diagnostic pop
#endif
std::unique_ptr<char[]> buf(new char[ size ] );
std::vsnprintf(buf.get(), size, format, args);
return std::string(buf.get(), buf.get() + size - 1 ); // We don't want the '\0' inside
#else
int size = _vscprintf(format, args);
std::string result(++size, 0);
vsnprintf_s((char*)result.data(), size, _TRUNCATE, format, args);
return result;
#endif
va_end(args);
}
int main() {
float f = 3.f;
int i = 5;
std::string s = "hello!";
auto rs = stringf("i=%d, f=%f, s=%s", i, f, s.c_str());
printf("%s", rs.c_str());
return 0;
}
Notes:
Separate VC++ code branch is necessary because VC++ has decided to deprecate snprintf which will generate compiler warnings for other highly voted answers above. As I always run in "warnings as errors" mode, its no go for me.
The function accepts char * instead of std::string. This because most of the time this function would be called with literal string which is indeed char *, not std::string. In case you do have std::string as format parameter, then just call .c_str().
Name of the function is stringf instead of things like string_format to keepup with printf, scanf etc.
It doesn't address safety issue (i.e. bad parameters can potentially cause seg fault instead of exception). If you need this then you are better off with boost or fmt libraries. My preference here would be fmt because it is just one header and source file to drop in the project while having less weird formatting syntax than boost. However both are non-compatible with printf format strings so below is still useful in that case.
The stringf code passes through GCC strict mode compilation. This requires extra #pragma macros to suppress false positives in GCC warnings.
Above code was tested on,
GCC 4.9.2/C++11/C++14
VC++ compiler ver 19.0
Clang 3.7.0
Below slightly modified version of #iFreilicht answer, updated to C++14 (usage of make_unique function instead of raw declaration) and added support for std::string arguments (based on Kenny Kerr article)
#include <iostream>
#include <memory>
#include <string>
#include <cstdio>
template <typename T>
T process_arg(T value) noexcept
{
return value;
}
template <typename T>
T const * process_arg(std::basic_string<T> const & value) noexcept
{
return value.c_str();
}
template<typename ... Args>
std::string string_format(const std::string& format, Args const & ... args)
{
const auto fmt = format.c_str();
const size_t size = std::snprintf(nullptr, 0, fmt, process_arg(args) ...) + 1;
auto buf = std::make_unique<char[]>(size);
std::snprintf(buf.get(), size, fmt, process_arg(args) ...);
auto res = std::string(buf.get(), buf.get() + size - 1);
return res;
}
int main()
{
int i = 3;
float f = 5.f;
char* s0 = "hello";
std::string s1 = "world";
std::cout << string_format("i=%d, f=%f, s=%s %s", i, f, s0, s1) << "\n";
}
Output:
i = 3, f = 5.000000, s = hello world
Feel free to merge this answer with the original one if desired.
UPDATE 1: added fmt::format tests
I've took my own investigation around methods has introduced here and gain diametrically opposite results versus mentioned here.
I have used 4 functions over 4 methods:
variadic function + vsnprintf + std::unique_ptr
variadic function + vsnprintf + std::string
variadic template function + std::ostringstream + std::tuple + utility::for_each
fmt::format function from fmt library
For the test backend the googletest has used.
#include <string>
#include <cstdarg>
#include <cstdlib>
#include <memory>
#include <algorithm>
#include <fmt/format.h>
inline std::string string_format(size_t string_reserve, const std::string fmt_str, ...)
{
size_t str_len = (std::max)(fmt_str.size(), string_reserve);
// plain buffer is a bit faster here than std::string::reserve
std::unique_ptr<char[]> formatted;
va_list ap;
va_start(ap, fmt_str);
while (true) {
formatted.reset(new char[str_len]);
const int final_n = vsnprintf(&formatted[0], str_len, fmt_str.c_str(), ap);
if (final_n < 0 || final_n >= int(str_len))
str_len += (std::abs)(final_n - int(str_len) + 1);
else
break;
}
va_end(ap);
return std::string(formatted.get());
}
inline std::string string_format2(size_t string_reserve, const std::string fmt_str, ...)
{
size_t str_len = (std::max)(fmt_str.size(), string_reserve);
std::string str;
va_list ap;
va_start(ap, fmt_str);
while (true) {
str.resize(str_len);
const int final_n = vsnprintf(const_cast<char *>(str.data()), str_len, fmt_str.c_str(), ap);
if (final_n < 0 || final_n >= int(str_len))
str_len += (std::abs)(final_n - int(str_len) + 1);
else {
str.resize(final_n); // do not forget to shrink the size!
break;
}
}
va_end(ap);
return str;
}
template <typename... Args>
inline std::string string_format3(size_t string_reserve, Args... args)
{
std::ostringstream ss;
if (string_reserve) {
ss.rdbuf()->str().reserve(string_reserve);
}
std::tuple<Args...> t{ args... };
utility::for_each(t, [&ss](auto & v)
{
ss << v;
});
return ss.str();
}
The for_each implementation is taken from here: iterate over tuple
#include <type_traits>
#include <tuple>
namespace utility {
template <std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
for_each(std::tuple<Tp...> &, const FuncT &)
{
}
template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
for_each(std::tuple<Tp...> & t, const FuncT & f)
{
f(std::get<I>(t));
for_each<I + 1, FuncT, Tp...>(t, f);
}
}
The tests:
TEST(ExternalFuncs, test_string_format_on_unique_ptr_0)
{
for (size_t i = 0; i < 1000000; i++) {
const std::string v = string_format(0, "%s+%u\n", "test test test", 12345);
UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR(v);
}
}
TEST(ExternalFuncs, test_string_format_on_unique_ptr_256)
{
for (size_t i = 0; i < 1000000; i++) {
const std::string v = string_format(256, "%s+%u\n", "test test test", 12345);
UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR(v);
}
}
TEST(ExternalFuncs, test_string_format_on_std_string_0)
{
for (size_t i = 0; i < 1000000; i++) {
const std::string v = string_format2(0, "%s+%u\n", "test test test", 12345);
UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR(v);
}
}
TEST(ExternalFuncs, test_string_format_on_std_string_256)
{
for (size_t i = 0; i < 1000000; i++) {
const std::string v = string_format2(256, "%s+%u\n", "test test test", 12345);
UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR(v);
}
}
TEST(ExternalFuncs, test_string_format_on_string_stream_on_variadic_tuple_0)
{
for (size_t i = 0; i < 1000000; i++) {
const std::string v = string_format3(0, "test test test", "+", 12345, "\n");
UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR(v);
}
}
TEST(ExternalFuncs, test_string_format_on_string_stream_on_variadic_tuple_256)
{
for (size_t i = 0; i < 1000000; i++) {
const std::string v = string_format3(256, "test test test", "+", 12345, "\n");
UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR(v);
}
}
TEST(ExternalFuncs, test_string_format_on_string_stream_inline_0)
{
for (size_t i = 0; i < 1000000; i++) {
std::ostringstream ss;
ss << "test test test" << "+" << 12345 << "\n";
const std::string v = ss.str();
UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR(v);
}
}
TEST(ExternalFuncs, test_string_format_on_string_stream_inline_256)
{
for (size_t i = 0; i < 1000000; i++) {
std::ostringstream ss;
ss.rdbuf()->str().reserve(256);
ss << "test test test" << "+" << 12345 << "\n";
const std::string v = ss.str();
UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR(v);
}
}
TEST(ExternalFuncs, test_fmt_format_positional)
{
for (size_t i = 0; i < 1000000; i++) {
const std::string v = fmt::format("{0:s}+{1:d}\n", "test test test", 12345);
UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR(v);
}
}
TEST(ExternalFuncs, test_fmt_format_named)
{
for (size_t i = 0; i < 1000000; i++) {
const std::string v = fmt::format("{first:s}+{second:d}\n", fmt::arg("first", "test test test"), fmt::arg("second", 12345));
UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR(v);
}
}
The UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR.
unsued.hpp:
#define UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR(var) ::utility::unused_param(&var)
namespace utility {
extern const volatile void * volatile g_unused_param_storage_ptr;
extern void
#ifdef __GNUC__
__attribute__((optimize("O0")))
#endif
unused_param(const volatile void * p);
}
unused.cpp:
namespace utility {
const volatile void * volatile g_unused_param_storage_ptr = nullptr;
void
#ifdef __GNUC__
__attribute__((optimize("O0")))
#endif
unused_param(const volatile void * p)
{
g_unused_param_storage_ptr = p;
}
}
RESULTS:
[ RUN ] ExternalFuncs.test_string_format_on_unique_ptr_0
[ OK ] ExternalFuncs.test_string_format_on_unique_ptr_0 (556 ms)
[ RUN ] ExternalFuncs.test_string_format_on_unique_ptr_256
[ OK ] ExternalFuncs.test_string_format_on_unique_ptr_256 (331 ms)
[ RUN ] ExternalFuncs.test_string_format_on_std_string_0
[ OK ] ExternalFuncs.test_string_format_on_std_string_0 (457 ms)
[ RUN ] ExternalFuncs.test_string_format_on_std_string_256
[ OK ] ExternalFuncs.test_string_format_on_std_string_256 (279 ms)
[ RUN ] ExternalFuncs.test_string_format_on_string_stream_on_variadic_tuple_0
[ OK ] ExternalFuncs.test_string_format_on_string_stream_on_variadic_tuple_0 (1214 ms)
[ RUN ] ExternalFuncs.test_string_format_on_string_stream_on_variadic_tuple_256
[ OK ] ExternalFuncs.test_string_format_on_string_stream_on_variadic_tuple_256 (1325 ms)
[ RUN ] ExternalFuncs.test_string_format_on_string_stream_inline_0
[ OK ] ExternalFuncs.test_string_format_on_string_stream_inline_0 (1208 ms)
[ RUN ] ExternalFuncs.test_string_format_on_string_stream_inline_256
[ OK ] ExternalFuncs.test_string_format_on_string_stream_inline_256 (1302 ms)
[ RUN ] ExternalFuncs.test_fmt_format_positional
[ OK ] ExternalFuncs.test_fmt_format_positional (288 ms)
[ RUN ] ExternalFuncs.test_fmt_format_named
[ OK ] ExternalFuncs.test_fmt_format_named (392 ms)
As you can see implementation through the vsnprintf+std::string is equal to fmt::format, but faster than through the vsnprintf+std::unique_ptr, which is faster than through the std::ostringstream.
The tests compiled in Visual Studio 2015 Update 3 and run at Windows 7 x64 / Intel Core i7-4820K CPU # 3.70GHz / 16GB.
Poco Foundation library has a very convenient format function, which supports std::string in both the format string and the values:
Doc: http://pocoproject.org/docs/Poco.html#7308
Source: https://github.com/pocoproject/poco/blob/develop/Foundation/src/Format.cpp
You can format C++ output in cout using iomanip header file.
Make sure that you include iomanip header file before you use any of the helper functions like
setprecision, setfill etc.
Here is a code snippet I have used in the past to print the average waiting time in the vector, which I have "accumulated".
#include<iomanip>
#include<iostream>
#include<vector>
#include<numeric>
...
cout<< "Average waiting times for tasks is " << setprecision(4) << accumulate(all(waitingTimes), 0)/double(waitingTimes.size()) ;
cout << " and " << Q.size() << " tasks remaining" << endl;
Here is a brief description of how we can format C++ streams.
http://www.cprogramming.com/tutorial/iomanip.html
There can be problems, if the buffer is not large enough to print the string. You must determine the length of the formatted string before printing a formatted message in there.
I make own helper to this (tested on Windows and Linux GCC), and you can try use it.
String.cpp: http://pastebin.com/DnfvzyKP
String.h: http://pastebin.com/7U6iCUMa
String.cpp:
#include <cstdio>
#include <cstdarg>
#include <cstring>
#include <string>
using ::std::string;
#pragma warning(disable : 4996)
#ifndef va_copy
#ifdef _MSC_VER
#define va_copy(dst, src) dst=src
#elif !(__cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__))
#define va_copy(dst, src) memcpy((void*)dst, (void*)src, sizeof(*src))
#endif
#endif
///
/// \breif Format message
/// \param dst String to store formatted message
/// \param format Format of message
/// \param ap Variable argument list
///
void toString(string &dst, const char *format, va_list ap) throw() {
int length;
va_list apStrLen;
va_copy(apStrLen, ap);
length = vsnprintf(NULL, 0, format, apStrLen);
va_end(apStrLen);
if (length > 0) {
dst.resize(length);
vsnprintf((char *)dst.data(), dst.size() + 1, format, ap);
} else {
dst = "Format error! format: ";
dst.append(format);
}
}
///
/// \breif Format message
/// \param dst String to store formatted message
/// \param format Format of message
/// \param ... Variable argument list
///
void toString(string &dst, const char *format, ...) throw() {
va_list ap;
va_start(ap, format);
toString(dst, format, ap);
va_end(ap);
}
///
/// \breif Format message
/// \param format Format of message
/// \param ... Variable argument list
///
string toString(const char *format, ...) throw() {
string dst;
va_list ap;
va_start(ap, format);
toString(dst, format, ap);
va_end(ap);
return dst;
}
///
/// \breif Format message
/// \param format Format of message
/// \param ap Variable argument list
///
string toString(const char *format, va_list ap) throw() {
string dst;
toString(dst, format, ap);
return dst;
}
int main() {
int a = 32;
const char * str = "This works!";
string test(toString("\nSome testing: a = %d, %s\n", a, str));
printf(test.c_str());
a = 0x7fffffff;
test = toString("\nMore testing: a = %d, %s\n", a, "This works too..");
printf(test.c_str());
a = 0x80000000;
toString(test, "\nMore testing: a = %d, %s\n", a, "This way is cheaper");
printf(test.c_str());
return 0;
}
String.h:
#pragma once
#include <cstdarg>
#include <string>
using ::std::string;
///
/// \breif Format message
/// \param dst String to store formatted message
/// \param format Format of message
/// \param ap Variable argument list
///
void toString(string &dst, const char *format, va_list ap) throw();
///
/// \breif Format message
/// \param dst String to store formatted message
/// \param format Format of message
/// \param ... Variable argument list
///
void toString(string &dst, const char *format, ...) throw();
///
/// \breif Format message
/// \param format Format of message
/// \param ... Variable argument list
///
string toString(const char *format, ...) throw();
///
/// \breif Format message
/// \param format Format of message
/// \param ap Variable argument list
///
string toString(const char *format, va_list ap) throw();
this can be tried out. simple. really does not use nuances of the string class though.
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string>
#include <exception>
using namespace std;
//---------------------------------------------------------------------
class StringFormatter
{
public:
static string format(const char *format, ...);
};
string StringFormatter::format(const char *format, ...)
{
va_list argptr;
va_start(argptr, format);
char *ptr;
size_t size;
FILE *fp_mem = open_memstream(&ptr, &size);
assert(fp_mem);
vfprintf (fp_mem, format, argptr);
fclose (fp_mem);
va_end(argptr);
string ret = ptr;
free(ptr);
return ret;
}
//---------------------------------------------------------------------
int main(void)
{
string temp = StringFormatter::format("my age is %d", 100);
printf("%s\n", temp.c_str());
return 0;
}
_return.desc = (boost::format("fail to detect. cv_result = %d") % st_result).str();
I want to use this library with MinGW and i've been trying to get the example to work.
Is this possible? I've had a look at using this but i've still not managed to do it.
Also, i'm welcome to alternative suggestions to sha1 hashing a string.
These are the errors I get when i try to compile sha1.cpp or the example program:
sha1.h:29:17: error: extra qualification 'SHA1::' on member 'lrot' [-fpermissive]
sha1.h:30:15: error: extra qualification 'SHA1::' on member 'storeBigEndianUint32' [-fpermissive]
sha1.h:31:15: error: extra qualification 'SHA1::' on member 'hexPrinter' [-fpermissive]
Thanks.
Part 2
#include <fstream>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include "sha1.h"
using namespace std;
int main(int argc, char *argv[])
{
const char* BYTES;
ifstream myFile("word.txt");
if (! myFile)
{
cout << "Error openning file" << endl;
return -1;
}
while (! myFile.eof())
{
getline(myFile, BYTES);
cout << BYTES << endl;
SHA1* sha1 = new SHA1();
sha1->addBytes(BYTES, strlen(BYTES));
unsigned char* digest = sha1->getDigest();
sha1->hexPrinter(digest, 20);
delete sha1;
free(digest);
}
myFile.close();
return 0;
}
I can vouch for Crypto++ and Botan. Both are great crypto libraries and I've used them both with Windows and mingw. They do sha1 and other hashes.
The problem is in the extra "SHA1::" in the following lines in the file SHA1.h:
static Uint32 SHA1::lrot( Uint32 x, int bits );
static void SHA1::storeBigEndianUint32( unsigned char* byte, Uint32 num );
static void SHA1::hexPrinter( unsigned char* c, int l );
They should be modified into
static Uint32 lrot( Uint32 x, int bits );
static void storeBigEndianUint32( unsigned char* byte, Uint32 num );
static void hexPrinter( unsigned char* c, int l );
This because the functions are being defined in the class SHA1 and is unnecessary to define again that they are in SHA1. Note that the same unmodified file may be accepted by Visual Studio (I had the same problem few years ago)
I have the following code:
[test.cpp]
#include <mcrypt.h>
#include <string>
#include <iostream>
#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <string>
using namespace std;
int main()
{
char algo[] = "rijndael-256";
char mode[] = "cbc";
char *block_buffer=(char*)"HELLO!! MY NAME IS: ";
cout<<"here"<<endl;
string s;
char key="1234-5678-9654-7512-7895-2543-12";
char iv[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};;
MCRYPT td = mcrypt_module_open(algo, NULL, mode, NULL);
if (td == MCRYPT_FAILED) { cout<<"error"<<endl;}
int keysize=32;
int r = mcrypt_generic_init(td, key, keysize, iv);
if (r<0)
{
cout<<"error2"<<endl;
mcrypt_perror(r);
return 1;
}
//while ( fread (&block_buffer, 1, 1, stdin) == 1 ) {
int j= mcrypt_generic (td, &block_buffer, sizeof(block_buffer));
if (j!=0){std::cout<<"error encrypting"<<std::endl;} // I HAVE ERROR HERE J==0
//how to print the encrypted string??
cout<<"buffer "<<block_buffer<<endl; //this is not the encriperd string. why?
mcrypt_generic_deinit(td);
mcrypt_module_close(td);
}
I am testing the code:
$: g++ test.cpp -o tst -lmcrypt
$: ./tst
WHERE SHOULT I ADD THE PKCS 7?
I have the following method:
std::string add_pkcs7_padding(std::string s, std::size_t n)
{
const std::size_t fill = n - (s.length() % n);
s.append(fill, static_cast<char>(fill));
return s;
}
std::string strip_pkcs7_padding(std::string s, std::size_t n)
{
const std::size_t pad = static_cast<unsigned char>(*s.rbegin());
return s.substr(0, s.length() - pad);
}
I din't know when should i run it and where in my code.
NEED SOME HELP. APPRECIATE A LOT!!
EDIT:
I have error at: mcrypt_generic (td, &block_buffer, sizeof(block_buffer)); The compiler prints
that the value j=0;
You should invoke mcrypt_generic() with a char*, not a char** as you do:
mcrypt_generic(td, block_buffer, sizeof(block_buffer));
^^^ ^^^^^^^^^^^^^^^^^^^^
ouch!
Also, the length is wrong, as sizeof(block_buffer) is just be the size of the pointer, not the string; if anything you need strlen(block_buffer).
But this is still going to be wrong in general because you need your message to be a multiple of the block size. Use the padding function:
std::string s = add_pkcs7_padding(block_buffer, mcrypt_enc_get_block_size(td));
std::vector<char> v(s.begin(), s.end()); // this will hold the encrypted data
mcrypt_generic(td, v.data(), v.size());
By the way, your plaintext should be declared like this:
const char * block_buffer = "HELLO!! MY NAME IS: ";
^^^^^ ^^^^
constness! no explicit cast!
But why so clumsy, it's better to just use a string:
std::string plaintext = "HELLO!! MY NAME IS: ";
I think you might benefit from picking up a good C++ book and familiarizing yourself with the basics of the language a bit - it's good to have a project to work on, but most of your problems aren't really related to encryption or mcrypt, but just general C++ programming.
I have to format std::string with sprintf and send it into file stream. How can I do this?
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:
#include <iostream>
#include <format>
int main() {
std::cout << std::format("Hello {}!\n", "world");
}
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 2021-11-28, partial support is available in Visual Studio 2019 16.10, which was released on 2021-05-25 and Clang 14, which is tracked here. In all other cases, you can resort to the C++11 solution below, or use the {fmt} library, which has the same semantics as std::format.
C++11
With C++11s std::snprintf, this already became a pretty easy and safe task.
#include <memory>
#include <string>
#include <stdexcept>
template<typename ... Args>
std::string string_format( const std::string& format, Args ... args )
{
int size_s = std::snprintf( nullptr, 0, format.c_str(), args ... ) + 1; // Extra space for '\0'
if( size_s <= 0 ){ throw std::runtime_error( "Error during formatting." ); }
auto size = static_cast<size_t>( size_s );
std::unique_ptr<char[]> buf( new char[ size ] );
std::snprintf( buf.get(), size, format.c_str(), args ... );
return std::string( buf.get(), buf.get() + size - 1 ); // We don't want the '\0' inside
}
The code snippet above is licensed under CC0 1.0.
Line by line explanation:
Aim: Write to a char* by using std::snprintf and then convert that to a std::string.
First, we determine the desired length of the char array using a special condition in snprintf. From cppreference.com:
Return value
[...] If the resulting string gets truncated due to buf_size limit,
function returns the total number of characters (not including the
terminating null-byte) which would have been written, if the limit was
not imposed.
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.
int size_s = std::snprintf( nullptr, 0, format.c_str(), args ... ) + 1;
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.
if( size_s <= 0 ){ throw std::runtime_error( "Error during formatting." ); }
Because we know that size_s can't be negative, we use a static cast to convert it from a signed int to an unsigned size_t. This way, even the most pedantic compiler won't complain about the conversions that would otherwise happen on the next lines.
size_t size = static_cast<size_t>( size_s );
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!
std::unique_ptr<char[]> buf( new char[ size ] );
In C++14, you could instead use make_unique, which is safe for user-defined types.
auto buf = std::make_unique<char[]>( size );
After that, we can of course just use snprintf for its intended use and write the formatted string to the char[].
std::snprintf( buf.get(), size, format.c_str(), args ... );
Finally, we create and return a new std::string from that, making sure to omit the null-terminator at the end.
return std::string( buf.get(), buf.get() + size - 1 );
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, without std::). 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:
#pragma warning(disable : 4996)
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.
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:
char buff[100];
snprintf(buff, sizeof(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();
C++11 solution that uses vsnprintf() internally:
#include <stdarg.h> // For va_start, etc.
std::string string_format(const std::string fmt, ...) {
int size = ((int)fmt.size()) * 2 + 50; // Use a rubric appropriate for your code
std::string str;
va_list ap;
while (1) { // Maximum two passes on a POSIX system...
str.resize(size);
va_start(ap, fmt);
int n = vsnprintf((char *)str.data(), size, fmt.c_str(), ap);
va_end(ap);
if (n > -1 && n < size) { // Everything worked
str.resize(n);
return str;
}
if (n > -1) // Needed size returned
size = n + 1; // For null char
else
size *= 2; // Guess at a larger size (OS specific)
}
return str;
}
A safer and more efficient (I tested it, and it is faster) approach:
#include <stdarg.h> // For va_start, etc.
#include <memory> // For std::unique_ptr
std::string string_format(const std::string fmt_str, ...) {
int final_n, n = ((int)fmt_str.size()) * 2; /* Reserve two times as much as the length of the fmt_str */
std::unique_ptr<char[]> formatted;
va_list ap;
while(1) {
formatted.reset(new char[n]); /* Wrap the plain char array into the unique_ptr */
strcpy(&formatted[0], fmt_str.c_str());
va_start(ap, fmt_str);
final_n = vsnprintf(&formatted[0], n, fmt_str.c_str(), ap);
va_end(ap);
if (final_n < 0 || final_n >= n)
n += abs(final_n - n + 1);
else
break;
}
return std::string(formatted.get());
}
The fmt_str is passed by value to conform with the requirements of va_start.
NOTE: The "safer" and "faster" version doesn't work on some systems. Hence both are still listed. Also, "faster" depends entirely on the preallocation step being correct, otherwise the strcpy renders it slower.
boost::format() provides the functionality you want:
As from the Boost format libraries synopsis:
A format object is constructed from a format-string, and is then given arguments through repeated calls to operator%.
Each of those arguments are then converted to strings, who are in turn combined into one string, according to the format-string.
#include <boost/format.hpp>
cout << boost::format("writing %1%, x=%2% : %3%-th try") % "toto" % 40.23 % 50;
// prints "writing toto, x=40.230 : 50-th try"
C++20 has std::format which resembles sprintf in terms of API but is fully type-safe, works with user-defined types, and uses Python-like format string syntax. Here's how you will be able to format std::string and write it to a stream:
std::string s = "foo";
std::cout << std::format("Look, a string: {}", s);
Alternatively, you could use the {fmt} library to format a string and write it to stdout or a file stream in one go:
fmt::print("Look, a string: {}", s);
As for sprintf or most of the other answers here, unfortunately they use varargs and are inherently unsafe unless you use something like GCC's format attribute which only works with literal format strings. You can see why these functions are unsafe on the following example:
std::string format_str = "%s";
string_format(format_str, format_str[0]);
where string_format is an implementation from the Erik Aronesty's answer. This code compiles, but it will most likely crash when you try to run it:
$ g++ -Wall -Wextra -pedantic test.cc
$ ./a.out
Segmentation fault: 11
Disclaimer: I'm the author of {fmt} and C++20 std::format.
I wrote my own using vsnprintf so it returns string instead of having to create my own buffer.
#include <string>
#include <cstdarg>
//missing string printf
//this is safe and convenient but not exactly efficient
inline std::string format(const char* fmt, ...){
int size = 512;
char* buffer = 0;
buffer = new char[size];
va_list vl;
va_start(vl, fmt);
int nsize = vsnprintf(buffer, size, fmt, vl);
if(size<=nsize){ //fail delete buffer and try again
delete[] buffer;
buffer = 0;
buffer = new char[nsize+1]; //+1 for /0
nsize = vsnprintf(buffer, size, fmt, vl);
}
std::string ret(buffer);
va_end(vl);
delete[] buffer;
return ret;
}
So you can use it like
std::string mystr = format("%s %d %10.5f", "omg", 1, 10.5);
Tested, Production Quality Answer
This answer handles the general case with standards compliant techniques. The same approach is given as an example on CppReference.com near the bottom of their page. Unlike their example, this code fits the question's requirements and is field tested in robotics and satellite applications. It also has improved commenting. Design quality is discussed further below.
#include <string>
#include <cstdarg>
#include <vector>
// requires at least C++11
const std::string vformat(const char * const zcFormat, ...) {
// initialize use of the variable argument array
va_list vaArgs;
va_start(vaArgs, zcFormat);
// reliably acquire the size
// from a copy of the variable argument array
// and a functionally reliable call to mock the formatting
va_list vaArgsCopy;
va_copy(vaArgsCopy, vaArgs);
const int iLen = std::vsnprintf(NULL, 0, zcFormat, vaArgsCopy);
va_end(vaArgsCopy);
// return a formatted string without risking memory mismanagement
// and without assuming any compiler or platform specific behavior
std::vector<char> zc(iLen + 1);
std::vsnprintf(zc.data(), zc.size(), zcFormat, vaArgs);
va_end(vaArgs);
return std::string(zc.data(), iLen); }
#include <ctime>
#include <iostream>
#include <iomanip>
// demonstration of use
int main() {
std::time_t t = std::time(nullptr);
std::cerr
<< std::put_time(std::localtime(& t), "%D %T")
<< " [debug]: "
<< vformat("Int 1 is %d, Int 2 is %d, Int 3 is %d", 11, 22, 33)
<< std::endl;
return 0; }
Predictable Linear Efficiency
Two passes are necessities for a secure, reliable, and predictable reusable function per the question specifications. Presumptions about the distribution of sizes of vargs in a reusable function is bad programming style and should be avoided. In this case, arbitrarily large variable length representations of vargs is a key factor in choice of algorithm.
Retrying upon overflow is exponentially inefficient, which is another reason discussed when the C++11 standards committee discussed the above proposal to provide a dry run when the write buffer is null.
In the above production ready implementation, the first run is such a dry run to determine allocation size. No allocation occurs. Parsing of printf directives and the reading of vargs has been made extremely efficient over decades. Reusable code should be predictable, even if a small inefficiency for trivial cases must be sacrificed.
Security and Reliability
Andrew Koenig said to a small group of us after his lecture at a Cambridge event, "User functions shouldn't rely on the exploitation of a failure for unexceptional functionality." As usual, his wisdom has been shown true in the record since. Fixed and closed security bug issues often indicate retry hacks in the description of the hole exploited prior to the fix.
This is mentioned in the formal standards revision proposal for the null buffer feature in Alternative to sprintf, C9X Revision Proposal, ISO IEC Document WG14 N645/X3J11 96-008. An arbitrarily long string inserted per print directive, "%s," within the constraints of dynamic memory availability, is not an exception, and should not be exploited to produce, "Unexceptional functionality."
Consider the proposal along side the example code given at the bottom of the C++Reference.org page linked to in the first paragraph of this answer.
Also, the testing of failure cases is rarely as robust of success cases.
Portability
All major O.S. vendors provide compilers that fully support std::vsnprintf as part of the c++11 standards. Hosts running products of vendors that no longer maintain distributions should be furnished with g++ or clang++ for many reasons.
Stack Use
Stack use in the 1st call to std::vsnprintf will be less than or equal to that of the 2nd, and and it will be freed before the 2nd call begins. If the first call exceeds stack availability, then std::fprintf would fail too.
In order to format std::string in a 'sprintf' manner, call snprintf (arguments nullptr and 0) to get length of buffer needed. Write your function using C++11 variadic template like this:
#include <cstdio>
#include <string>
#include <cassert>
template< typename... Args >
std::string string_sprintf( const char* format, Args... args ) {
int length = std::snprintf( nullptr, 0, format, args... );
assert( length >= 0 );
char* buf = new char[length + 1];
std::snprintf( buf, length + 1, format, args... );
std::string str( buf );
delete[] buf;
return str;
}
Compile with C++11 support, for example in GCC: g++ -std=c++11
Usage:
std::cout << string_sprintf("%g, %g\n", 1.23, 0.001);
If you only want a printf-like syntax (without calling printf yourself), have a look at Boost Format.
C++20 std::format
It has arrived! The feature is described at: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0645r9.html and uses a Python-like .format() syntax.
I expect that the usage will be like:
#include <format>
#include <string>
int main() {
std::string message = std::format("The answer is {}.", 42);
}
GCC 9.1.0 with g++-9 -std=c++2a still doesn't support it.
The existing fmt library implements it for before it gets official support: https://github.com/fmtlib/fmt as previously mentioned at: std::string formatting like sprintf Install on Ubuntu 22.04:
sudo apt install libfmt-dev
Modify source to replace:
<format> with <fmt/core.h>
std::format to fmt::format
main.cpp
#include <string>
#include <iostream>
#include <fmt/core.h>
int main() {
std::string message = fmt::format("The answer is {}.", 42);
std::cout << message << std::endl;
}
and compile and run with:
g++ -std=c++11 -o main.out main.cpp -lfmt
./main.out
Output:
The answer is 42.
The API will add a new std::format header:
The proposed formatting API is defined in the new header <format> and should have no impact on existing code.
Hexadecimal format {:x}
C++ cout hex values?
Leading zeroes {:03}
Print leading zeros with C++ output operator?
Alignment left {:<}, right {:>}, center {:^}
C++ alignment when printing cout <<
Floating point precision {:.2}
How do I print a double value with full precision using cout?
Set back default floating point print precision in C++
Show sign on positive numbers {:+}
How to print positive numbers with a prefix + in C++
Show booleans as true and false: {:}
Converting bool to text in C++
[edit: 20/05/25] better still...:
In header:
// `say` prints the values
// `says` returns a string instead of printing
// `sayss` appends the values to it's first argument instead of printing
// `sayerr` prints the values and returns `false` (useful for return statement fail-report)<br/>
void PRINTSTRING(const std::string &s); //cater for GUI, terminal, whatever..
template<typename...P> void say(P...p) { std::string r{}; std::stringstream ss(""); (ss<<...<<p); r=ss.str(); PRINTSTRING(r); }
template<typename...P> std::string says(P...p) { std::string r{}; std::stringstream ss(""); (ss<<...<<p); r=ss.str(); return r; }
template<typename...P> void sayss(std::string &s, P...p) { std::string r{}; std::stringstream ss(""); (ss<<...<<p); r=ss.str(); s+=r; } //APPENDS! to s!
template<typename...P> bool sayerr(P...p) { std::string r{}; std::stringstream ss("ERROR: "); (ss<<...<<p); r=ss.str(); PRINTSTRING(r); return false; }
The PRINTSTRING(r)-function is to cater for GUI or terminal or any special output needs using #ifdef _some_flag_, the default is:
void PRINTSTRING(const std::string &s) { std::cout << s << std::flush; }
[edit '17/8/31] Adding a variadic templated version 'vtspf(..)':
template<typename T> const std::string type_to_string(const T &v)
{
std::ostringstream ss;
ss << v;
return ss.str();
};
template<typename T> const T string_to_type(const std::string &str)
{
std::istringstream ss(str);
T ret;
ss >> ret;
return ret;
};
template<typename...P> void vtspf_priv(std::string &s) {}
template<typename H, typename...P> void vtspf_priv(std::string &s, H h, P...p)
{
s+=type_to_string(h);
vtspf_priv(s, p...);
}
template<typename...P> std::string temp_vtspf(P...p)
{
std::string s("");
vtspf_priv(s, p...);
return s;
}
which is effectively a comma-delimited version (instead) of the sometimes hindering <<-operators, used like this:
char chSpace=' ';
double pi=3.1415;
std::string sWorld="World", str_var;
str_var = vtspf("Hello", ',', chSpace, sWorld, ", pi=", pi);
[edit] Adapted to make use of the technique in Erik Aronesty's answer (above):
#include <string>
#include <cstdarg>
#include <cstdio>
//=============================================================================
void spf(std::string &s, const std::string fmt, ...)
{
int n, size=100;
bool b=false;
va_list marker;
while (!b)
{
s.resize(size);
va_start(marker, fmt);
n = vsnprintf((char*)s.c_str(), size, fmt.c_str(), marker);
va_end(marker);
if ((n>0) && ((b=(n<size))==true)) s.resize(n); else size*=2;
}
}
//=============================================================================
void spfa(std::string &s, const std::string fmt, ...)
{
std::string ss;
int n, size=100;
bool b=false;
va_list marker;
while (!b)
{
ss.resize(size);
va_start(marker, fmt);
n = vsnprintf((char*)ss.c_str(), size, fmt.c_str(), marker);
va_end(marker);
if ((n>0) && ((b=(n<size))==true)) ss.resize(n); else size*=2;
}
s += ss;
}
[previous answer]
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(std::string& sF, const char* sformat, va_list marker)
{
char *s, ch=0;
int n, i=0, m;
long l;
double d;
std::string sf = sformat;
std::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 'X':
case 'x':
{
if (++i<m)
{
ss << std::hex << std::setiosflags (std::ios_base::showbase);
if (ch == 'X') ss << std::setiosflags (std::ios_base::uppercase);
char ch2 = sf.at(i);
if (ch2 == 'c') { n = va_arg(marker, int); ss << std::hex << (char)n; }
else if (ch2 == 'd') { n = va_arg(marker, int); ss << std::hex << (int)n; }
else if (ch2 == 'l') { l = va_arg(marker, long); ss << std::hex << (long)l; }
else ss << '%' << ch << ch2;
ss << std::resetiosflags (std::ios_base::showbase | std::ios_base::uppercase) << std::dec;
}
} break;
case '%': { ss << '%'; } break;
default:
{
ss << "%" << ch;
//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;
}
template<typename... Args>
std::string string_format(const char* fmt, Args... args)
{
size_t size = snprintf(nullptr, 0, fmt, args...);
std::string buf;
buf.reserve(size + 1);
buf.resize(size);
snprintf(&buf[0], size + 1, fmt, args...);
return buf;
}
Using C99 snprintf and C++11
This is how google does it: StringPrintf (BSD License)
and facebook does it in a quite similar fashion: StringPrintf (Apache License)
Both provide with a convenient StringAppendF too.
My two cents on this very popular question.
To quote the manpage of printf-like functions:
Upon successful return, these functions return the number of characters printed (excluding the null byte used to end output to strings).
The functions snprintf() and vsnprintf() do not write more than size bytes (including the terminating null byte ('\0')). If the output was truncated due to this limit then the return value is the number of characters (excluding the terminating null byte) which would have been written to the final string if enough space had been available. Thus, a return value of size or more means that the output was truncated.
In other words, a sane C++11 implementation should be the following:
#include <string>
#include <cstdio>
template <typename... Ts>
std::string fmt (const std::string &fmt, Ts... vs)
{
char b;
size_t required = std::snprintf(&b, 0, fmt.c_str(), vs...) + 1;
// See comments: the +1 is necessary, while the first parameter
// can also be set to nullptr
char bytes[required];
std::snprintf(bytes, required, fmt.c_str(), vs...);
return std::string(bytes);
}
It works quite well :)
Variadic templates are supported only in C++11. The answer from pixelpoint show a similar technique using older programming styles.
It's weird that C++ does not have such a thing out of the box. They recently added to_string(), which in my opinion is a great step forward. I'm wondering if they will add a .format operator to the std::string eventually...
Edit
As alexk7 pointed out, A +1 is needed on the return value of std::snprintf, since we need to have space for the \0 byte. Intuitively, on most architectures missing the +1 will cause the required integer to be partially overwritten with a 0. This will happen after the evaluation of required as actual parameter for std::snprintf, so the effect should not be visible.
This problem could however change, for instance with compiler optimization: what if the compiler decides to use a register for the required variable? This is the kind of errors which sometimes result in security issues.
If you are on a system that has asprintf(3), you can easily wrap it:
#include <iostream>
#include <cstdarg>
#include <cstdio>
std::string format(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
std::string format(const char *fmt, ...)
{
std::string result;
va_list ap;
va_start(ap, fmt);
char *tmp = 0;
int res = vasprintf(&tmp, fmt, ap);
va_end(ap);
if (res != -1) {
result = tmp;
free(tmp);
} else {
// The vasprintf call failed, either do nothing and
// fall through (will return empty string) or
// throw an exception, if your code uses those
}
return result;
}
int main(int argc, char *argv[]) {
std::string username = "you";
std::cout << format("Hello %s! %d", username.c_str(), 123) << std::endl;
return 0;
}
Based on the answer provided by Erik Aronesty:
std::string string_format(const std::string &fmt, ...) {
std::vector<char> str(100,'\0');
va_list ap;
while (1) {
va_start(ap, fmt);
auto n = vsnprintf(str.data(), str.size(), fmt.c_str(), ap);
va_end(ap);
if ((n > -1) && (size_t(n) < str.size())) {
return str.data();
}
if (n > -1)
str.resize( n + 1 );
else
str.resize( str.size() * 2);
}
return str.data();
}
This avoids the need to cast away const from the result of .c_str() which was in the original answer.
inline void format(string& a_string, const char* fmt, ...)
{
va_list vl;
va_start(vl, fmt);
int size = _vscprintf( fmt, vl );
a_string.resize( ++size );
vsnprintf_s((char*)a_string.data(), size, _TRUNCATE, fmt, vl);
va_end(vl);
}
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.
You could try this:
string str;
str.resize( _MAX_PATH );
sprintf( &str[0], "%s %s", "hello", "world" );
// optionals
// sprintf_s( &str[0], str.length(), "%s %s", "hello", "world" ); // Microsoft
// #include <stdio.h>
// snprintf( &str[0], str.length(), "%s %s", "hello", "world" ); // c++11
str.resize( strlen( str.data() ) + 1 );
I usually use this:
std::string myformat(const char *const fmt, ...)
{
char *buffer = NULL;
va_list ap;
va_start(ap, fmt);
(void)vasprintf(&buffer, fmt, ap);
va_end(ap);
std::string result = buffer;
free(buffer);
return result;
}
Disadvantage: not all systems support vasprint
This is the code I use to do this in my program... It's nothing fancy, but it does the trick... Note, you will have to adjust your size as applicable. MAX_BUFFER for me is 1024.
std::string Format ( const char *fmt, ... )
{
char textString[MAX_BUFFER*5] = {'\0'};
// -- Empty the buffer properly to ensure no leaks.
memset(textString, '\0', sizeof(textString));
va_list args;
va_start ( args, fmt );
vsnprintf ( textString, MAX_BUFFER*5, fmt, args );
va_end ( args );
std::string retStr = textString;
return retStr;
}
Took the idea from Dacav and pixelpoint's answer. I played around a bit and got this:
#include <cstdarg>
#include <cstdio>
#include <string>
std::string format(const char* fmt, ...)
{
va_list vl;
va_start(vl, fmt);
int size = vsnprintf(0, 0, fmt, vl) + sizeof('\0');
va_end(vl);
char buffer[size];
va_start(vl, fmt);
size = vsnprintf(buffer, size, fmt, vl);
va_end(vl);
return std::string(buffer, size);
}
With sane programming practice I believe the code should be enough, however I'm still open to more secure alternatives that are still simple enough and would not require C++11.
And here's another version that makes use of an initial buffer to prevent second call to vsnprintf() when initial buffer is already enough.
std::string format(const char* fmt, ...)
{
va_list vl;
int size;
enum { INITIAL_BUFFER_SIZE = 512 };
{
char buffer[INITIAL_BUFFER_SIZE];
va_start(vl, fmt);
size = vsnprintf(buffer, INITIAL_BUFFER_SIZE, fmt, vl);
va_end(vl);
if (size < INITIAL_BUFFER_SIZE)
return std::string(buffer, size);
}
size += sizeof('\0');
char buffer[size];
va_start(vl, fmt);
size = vsnprintf(buffer, size, fmt, vl);
va_end(vl);
return std::string(buffer, size);
}
(It turns out that this version is just similar to Piti Ongmongkolkul's answer, only that it doesn't use new and delete[], and also specifies a size when creating std::string.
The idea here of not using new and delete[] is to imply usage of the stack over the heap since it doesn't need to call allocation and deallocation functions, however if not properly used, it could be dangerous to buffer overflows in some (perhaps old, or perhaps just vulnerable) systems. If this is a concern, I highly suggest using new and delete[] instead. Note that the only concern here is about the allocations as vsnprintf() is already called with limits, so specifying a limit based on the size allocated on the second buffer would also prevent those.)
All the answers so far here seems to have one or more of these problems: (1) it may not work on VC++ (2) it requires additional dependencies like boost or fmt (3) its too complicated custom implementation and probably not tested well.
Below code addresses all of above issues.
#include <string>
#include <cstdarg>
#include <memory>
std::string stringf(const char* format, ...)
{
va_list args;
va_start(args, format);
#ifndef _MSC_VER
//GCC generates warning for valid use of snprintf to get
//size of result string. We suppress warning with below macro.
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
#endif
size_t size = std::snprintf(nullptr, 0, format, args) + 1; // Extra space for '\0'
#ifdef __GNUC__
# pragma GCC diagnostic pop
#endif
std::unique_ptr<char[]> buf(new char[ size ] );
std::vsnprintf(buf.get(), size, format, args);
return std::string(buf.get(), buf.get() + size - 1 ); // We don't want the '\0' inside
#else
int size = _vscprintf(format, args);
std::string result(++size, 0);
vsnprintf_s((char*)result.data(), size, _TRUNCATE, format, args);
return result;
#endif
va_end(args);
}
int main() {
float f = 3.f;
int i = 5;
std::string s = "hello!";
auto rs = stringf("i=%d, f=%f, s=%s", i, f, s.c_str());
printf("%s", rs.c_str());
return 0;
}
Notes:
Separate VC++ code branch is necessary because VC++ has decided to deprecate snprintf which will generate compiler warnings for other highly voted answers above. As I always run in "warnings as errors" mode, its no go for me.
The function accepts char * instead of std::string. This because most of the time this function would be called with literal string which is indeed char *, not std::string. In case you do have std::string as format parameter, then just call .c_str().
Name of the function is stringf instead of things like string_format to keepup with printf, scanf etc.
It doesn't address safety issue (i.e. bad parameters can potentially cause seg fault instead of exception). If you need this then you are better off with boost or fmt libraries. My preference here would be fmt because it is just one header and source file to drop in the project while having less weird formatting syntax than boost. However both are non-compatible with printf format strings so below is still useful in that case.
The stringf code passes through GCC strict mode compilation. This requires extra #pragma macros to suppress false positives in GCC warnings.
Above code was tested on,
GCC 4.9.2/C++11/C++14
VC++ compiler ver 19.0
Clang 3.7.0
Below slightly modified version of #iFreilicht answer, updated to C++14 (usage of make_unique function instead of raw declaration) and added support for std::string arguments (based on Kenny Kerr article)
#include <iostream>
#include <memory>
#include <string>
#include <cstdio>
template <typename T>
T process_arg(T value) noexcept
{
return value;
}
template <typename T>
T const * process_arg(std::basic_string<T> const & value) noexcept
{
return value.c_str();
}
template<typename ... Args>
std::string string_format(const std::string& format, Args const & ... args)
{
const auto fmt = format.c_str();
const size_t size = std::snprintf(nullptr, 0, fmt, process_arg(args) ...) + 1;
auto buf = std::make_unique<char[]>(size);
std::snprintf(buf.get(), size, fmt, process_arg(args) ...);
auto res = std::string(buf.get(), buf.get() + size - 1);
return res;
}
int main()
{
int i = 3;
float f = 5.f;
char* s0 = "hello";
std::string s1 = "world";
std::cout << string_format("i=%d, f=%f, s=%s %s", i, f, s0, s1) << "\n";
}
Output:
i = 3, f = 5.000000, s = hello world
Feel free to merge this answer with the original one if desired.
UPDATE 1: added fmt::format tests
I've took my own investigation around methods has introduced here and gain diametrically opposite results versus mentioned here.
I have used 4 functions over 4 methods:
variadic function + vsnprintf + std::unique_ptr
variadic function + vsnprintf + std::string
variadic template function + std::ostringstream + std::tuple + utility::for_each
fmt::format function from fmt library
For the test backend the googletest has used.
#include <string>
#include <cstdarg>
#include <cstdlib>
#include <memory>
#include <algorithm>
#include <fmt/format.h>
inline std::string string_format(size_t string_reserve, const std::string fmt_str, ...)
{
size_t str_len = (std::max)(fmt_str.size(), string_reserve);
// plain buffer is a bit faster here than std::string::reserve
std::unique_ptr<char[]> formatted;
va_list ap;
va_start(ap, fmt_str);
while (true) {
formatted.reset(new char[str_len]);
const int final_n = vsnprintf(&formatted[0], str_len, fmt_str.c_str(), ap);
if (final_n < 0 || final_n >= int(str_len))
str_len += (std::abs)(final_n - int(str_len) + 1);
else
break;
}
va_end(ap);
return std::string(formatted.get());
}
inline std::string string_format2(size_t string_reserve, const std::string fmt_str, ...)
{
size_t str_len = (std::max)(fmt_str.size(), string_reserve);
std::string str;
va_list ap;
va_start(ap, fmt_str);
while (true) {
str.resize(str_len);
const int final_n = vsnprintf(const_cast<char *>(str.data()), str_len, fmt_str.c_str(), ap);
if (final_n < 0 || final_n >= int(str_len))
str_len += (std::abs)(final_n - int(str_len) + 1);
else {
str.resize(final_n); // do not forget to shrink the size!
break;
}
}
va_end(ap);
return str;
}
template <typename... Args>
inline std::string string_format3(size_t string_reserve, Args... args)
{
std::ostringstream ss;
if (string_reserve) {
ss.rdbuf()->str().reserve(string_reserve);
}
std::tuple<Args...> t{ args... };
utility::for_each(t, [&ss](auto & v)
{
ss << v;
});
return ss.str();
}
The for_each implementation is taken from here: iterate over tuple
#include <type_traits>
#include <tuple>
namespace utility {
template <std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
for_each(std::tuple<Tp...> &, const FuncT &)
{
}
template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
for_each(std::tuple<Tp...> & t, const FuncT & f)
{
f(std::get<I>(t));
for_each<I + 1, FuncT, Tp...>(t, f);
}
}
The tests:
TEST(ExternalFuncs, test_string_format_on_unique_ptr_0)
{
for (size_t i = 0; i < 1000000; i++) {
const std::string v = string_format(0, "%s+%u\n", "test test test", 12345);
UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR(v);
}
}
TEST(ExternalFuncs, test_string_format_on_unique_ptr_256)
{
for (size_t i = 0; i < 1000000; i++) {
const std::string v = string_format(256, "%s+%u\n", "test test test", 12345);
UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR(v);
}
}
TEST(ExternalFuncs, test_string_format_on_std_string_0)
{
for (size_t i = 0; i < 1000000; i++) {
const std::string v = string_format2(0, "%s+%u\n", "test test test", 12345);
UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR(v);
}
}
TEST(ExternalFuncs, test_string_format_on_std_string_256)
{
for (size_t i = 0; i < 1000000; i++) {
const std::string v = string_format2(256, "%s+%u\n", "test test test", 12345);
UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR(v);
}
}
TEST(ExternalFuncs, test_string_format_on_string_stream_on_variadic_tuple_0)
{
for (size_t i = 0; i < 1000000; i++) {
const std::string v = string_format3(0, "test test test", "+", 12345, "\n");
UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR(v);
}
}
TEST(ExternalFuncs, test_string_format_on_string_stream_on_variadic_tuple_256)
{
for (size_t i = 0; i < 1000000; i++) {
const std::string v = string_format3(256, "test test test", "+", 12345, "\n");
UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR(v);
}
}
TEST(ExternalFuncs, test_string_format_on_string_stream_inline_0)
{
for (size_t i = 0; i < 1000000; i++) {
std::ostringstream ss;
ss << "test test test" << "+" << 12345 << "\n";
const std::string v = ss.str();
UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR(v);
}
}
TEST(ExternalFuncs, test_string_format_on_string_stream_inline_256)
{
for (size_t i = 0; i < 1000000; i++) {
std::ostringstream ss;
ss.rdbuf()->str().reserve(256);
ss << "test test test" << "+" << 12345 << "\n";
const std::string v = ss.str();
UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR(v);
}
}
TEST(ExternalFuncs, test_fmt_format_positional)
{
for (size_t i = 0; i < 1000000; i++) {
const std::string v = fmt::format("{0:s}+{1:d}\n", "test test test", 12345);
UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR(v);
}
}
TEST(ExternalFuncs, test_fmt_format_named)
{
for (size_t i = 0; i < 1000000; i++) {
const std::string v = fmt::format("{first:s}+{second:d}\n", fmt::arg("first", "test test test"), fmt::arg("second", 12345));
UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR(v);
}
}
The UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR.
unsued.hpp:
#define UTILITY_SUPPRESS_OPTIMIZATION_ON_VAR(var) ::utility::unused_param(&var)
namespace utility {
extern const volatile void * volatile g_unused_param_storage_ptr;
extern void
#ifdef __GNUC__
__attribute__((optimize("O0")))
#endif
unused_param(const volatile void * p);
}
unused.cpp:
namespace utility {
const volatile void * volatile g_unused_param_storage_ptr = nullptr;
void
#ifdef __GNUC__
__attribute__((optimize("O0")))
#endif
unused_param(const volatile void * p)
{
g_unused_param_storage_ptr = p;
}
}
RESULTS:
[ RUN ] ExternalFuncs.test_string_format_on_unique_ptr_0
[ OK ] ExternalFuncs.test_string_format_on_unique_ptr_0 (556 ms)
[ RUN ] ExternalFuncs.test_string_format_on_unique_ptr_256
[ OK ] ExternalFuncs.test_string_format_on_unique_ptr_256 (331 ms)
[ RUN ] ExternalFuncs.test_string_format_on_std_string_0
[ OK ] ExternalFuncs.test_string_format_on_std_string_0 (457 ms)
[ RUN ] ExternalFuncs.test_string_format_on_std_string_256
[ OK ] ExternalFuncs.test_string_format_on_std_string_256 (279 ms)
[ RUN ] ExternalFuncs.test_string_format_on_string_stream_on_variadic_tuple_0
[ OK ] ExternalFuncs.test_string_format_on_string_stream_on_variadic_tuple_0 (1214 ms)
[ RUN ] ExternalFuncs.test_string_format_on_string_stream_on_variadic_tuple_256
[ OK ] ExternalFuncs.test_string_format_on_string_stream_on_variadic_tuple_256 (1325 ms)
[ RUN ] ExternalFuncs.test_string_format_on_string_stream_inline_0
[ OK ] ExternalFuncs.test_string_format_on_string_stream_inline_0 (1208 ms)
[ RUN ] ExternalFuncs.test_string_format_on_string_stream_inline_256
[ OK ] ExternalFuncs.test_string_format_on_string_stream_inline_256 (1302 ms)
[ RUN ] ExternalFuncs.test_fmt_format_positional
[ OK ] ExternalFuncs.test_fmt_format_positional (288 ms)
[ RUN ] ExternalFuncs.test_fmt_format_named
[ OK ] ExternalFuncs.test_fmt_format_named (392 ms)
As you can see implementation through the vsnprintf+std::string is equal to fmt::format, but faster than through the vsnprintf+std::unique_ptr, which is faster than through the std::ostringstream.
The tests compiled in Visual Studio 2015 Update 3 and run at Windows 7 x64 / Intel Core i7-4820K CPU # 3.70GHz / 16GB.
Poco Foundation library has a very convenient format function, which supports std::string in both the format string and the values:
Doc: http://pocoproject.org/docs/Poco.html#7308
Source: https://github.com/pocoproject/poco/blob/develop/Foundation/src/Format.cpp
You can format C++ output in cout using iomanip header file.
Make sure that you include iomanip header file before you use any of the helper functions like
setprecision, setfill etc.
Here is a code snippet I have used in the past to print the average waiting time in the vector, which I have "accumulated".
#include<iomanip>
#include<iostream>
#include<vector>
#include<numeric>
...
cout<< "Average waiting times for tasks is " << setprecision(4) << accumulate(all(waitingTimes), 0)/double(waitingTimes.size()) ;
cout << " and " << Q.size() << " tasks remaining" << endl;
Here is a brief description of how we can format C++ streams.
http://www.cprogramming.com/tutorial/iomanip.html
There can be problems, if the buffer is not large enough to print the string. You must determine the length of the formatted string before printing a formatted message in there.
I make own helper to this (tested on Windows and Linux GCC), and you can try use it.
String.cpp: http://pastebin.com/DnfvzyKP
String.h: http://pastebin.com/7U6iCUMa
String.cpp:
#include <cstdio>
#include <cstdarg>
#include <cstring>
#include <string>
using ::std::string;
#pragma warning(disable : 4996)
#ifndef va_copy
#ifdef _MSC_VER
#define va_copy(dst, src) dst=src
#elif !(__cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__))
#define va_copy(dst, src) memcpy((void*)dst, (void*)src, sizeof(*src))
#endif
#endif
///
/// \breif Format message
/// \param dst String to store formatted message
/// \param format Format of message
/// \param ap Variable argument list
///
void toString(string &dst, const char *format, va_list ap) throw() {
int length;
va_list apStrLen;
va_copy(apStrLen, ap);
length = vsnprintf(NULL, 0, format, apStrLen);
va_end(apStrLen);
if (length > 0) {
dst.resize(length);
vsnprintf((char *)dst.data(), dst.size() + 1, format, ap);
} else {
dst = "Format error! format: ";
dst.append(format);
}
}
///
/// \breif Format message
/// \param dst String to store formatted message
/// \param format Format of message
/// \param ... Variable argument list
///
void toString(string &dst, const char *format, ...) throw() {
va_list ap;
va_start(ap, format);
toString(dst, format, ap);
va_end(ap);
}
///
/// \breif Format message
/// \param format Format of message
/// \param ... Variable argument list
///
string toString(const char *format, ...) throw() {
string dst;
va_list ap;
va_start(ap, format);
toString(dst, format, ap);
va_end(ap);
return dst;
}
///
/// \breif Format message
/// \param format Format of message
/// \param ap Variable argument list
///
string toString(const char *format, va_list ap) throw() {
string dst;
toString(dst, format, ap);
return dst;
}
int main() {
int a = 32;
const char * str = "This works!";
string test(toString("\nSome testing: a = %d, %s\n", a, str));
printf(test.c_str());
a = 0x7fffffff;
test = toString("\nMore testing: a = %d, %s\n", a, "This works too..");
printf(test.c_str());
a = 0x80000000;
toString(test, "\nMore testing: a = %d, %s\n", a, "This way is cheaper");
printf(test.c_str());
return 0;
}
String.h:
#pragma once
#include <cstdarg>
#include <string>
using ::std::string;
///
/// \breif Format message
/// \param dst String to store formatted message
/// \param format Format of message
/// \param ap Variable argument list
///
void toString(string &dst, const char *format, va_list ap) throw();
///
/// \breif Format message
/// \param dst String to store formatted message
/// \param format Format of message
/// \param ... Variable argument list
///
void toString(string &dst, const char *format, ...) throw();
///
/// \breif Format message
/// \param format Format of message
/// \param ... Variable argument list
///
string toString(const char *format, ...) throw();
///
/// \breif Format message
/// \param format Format of message
/// \param ap Variable argument list
///
string toString(const char *format, va_list ap) throw();
this can be tried out. simple. really does not use nuances of the string class though.
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string>
#include <exception>
using namespace std;
//---------------------------------------------------------------------
class StringFormatter
{
public:
static string format(const char *format, ...);
};
string StringFormatter::format(const char *format, ...)
{
va_list argptr;
va_start(argptr, format);
char *ptr;
size_t size;
FILE *fp_mem = open_memstream(&ptr, &size);
assert(fp_mem);
vfprintf (fp_mem, format, argptr);
fclose (fp_mem);
va_end(argptr);
string ret = ptr;
free(ptr);
return ret;
}
//---------------------------------------------------------------------
int main(void)
{
string temp = StringFormatter::format("my age is %d", 100);
printf("%s\n", temp.c_str());
return 0;
}
_return.desc = (boost::format("fail to detect. cv_result = %d") % st_result).str();