Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Here's the idiom I like for making functionality identical to 'sprintf', but returning a std::string, and immune to buffer overflow problems. This code is part of an open source project that I'm writing (BSD license), so everybody feel free to use this as you wish.</p> <pre><code>#include &lt;string&gt; #include &lt;cstdarg&gt; #include &lt;vector&gt; #include &lt;string&gt; std::string format (const char *fmt, ...) { va_list ap; va_start (ap, fmt); std::string buf = vformat (fmt, ap); va_end (ap); return buf; } std::string vformat (const char *fmt, va_list ap) { // Allocate a buffer on the stack that's big enough for us almost // all the time. size_t size = 1024; char buf[size]; // Try to vsnprintf into our buffer. va_list apcopy; va_copy (apcopy, ap); int needed = vsnprintf (&amp;buf[0], size, fmt, ap); // NB. On Windows, vsnprintf returns -1 if the string didn't fit the // buffer. On Linux &amp; OSX, it returns the length it would have needed. if (needed &lt;= size &amp;&amp; needed &gt;= 0) { // It fit fine the first time, we're done. return std::string (&amp;buf[0]); } else { // vsnprintf reported that it wanted to write more characters // than we allotted. So do a malloc of the right size and try again. // This doesn't happen very often if we chose our initial size // well. std::vector &lt;char&gt; buf; size = needed; buf.resize (size); needed = vsnprintf (&amp;buf[0], size, fmt, apcopy); return std::string (&amp;buf[0]); } } </code></pre> <p>EDIT: when I wrote this code, I had no idea that this required C99 conformance and that Windows (as well as older glibc) had different vsnprintf behavior, in which it returns -1 for failure, rather than a definitive measure of how much space is needed. Here is my revised code, could everybody look it over and if you think it's ok, I will edit again to make that the only cost listed:</p> <pre><code>std::string Strutil::vformat (const char *fmt, va_list ap) { // Allocate a buffer on the stack that's big enough for us almost // all the time. Be prepared to allocate dynamically if it doesn't fit. size_t size = 1024; char stackbuf[1024]; std::vector&lt;char&gt; dynamicbuf; char *buf = &amp;stackbuf[0]; va_list ap_copy; while (1) { // Try to vsnprintf into our buffer. va_copy(ap_copy, ap); int needed = vsnprintf (buf, size, fmt, ap); va_end(ap_copy); // NB. C99 (which modern Linux and OS X follow) says vsnprintf // failure returns the length it would have needed. But older // glibc and current Windows return -1 for failure, i.e., not // telling us how much was needed. if (needed &lt;= (int)size &amp;&amp; needed &gt;= 0) { // It fit fine so we're done. return std::string (buf, (size_t) needed); } // vsnprintf reported that it wanted to write more characters // than we allotted. So try again using a dynamic buffer. This // doesn't happen very often if we chose our initial size well. size = (needed &gt; 0) ? (needed+1) : (size*2); dynamicbuf.resize (size); buf = &amp;dynamicbuf[0]; } } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload