Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I'm looking at optimizing some string formatting code that's hit a lot in our code. We had been using ostringstream, and I converted the code to use sprintf (actually Microsoft's more secure sprintf_s). I've traded type safety for run-time performance. But I've debugged enough sprintf related weird crashes to know that sprintf has its own serious flaws that the compile time checking of ostringstream catch. But ostringstream is more than an order-of-magnitude slower then sprintf by my measure, and that's not tolerable in this code. I'm also not thrilled with the readability of C++ stream string formatting, but this may be entirely subjective.

So unfortunately when formatting strings in C++ I've got several "standard" options that are suboptimal:

  1. sprintf -- fast, but not type safe. Can have insidious bugs when the wrong format string is not used.
  2. ostringstream -- slow, but type safe. IMO Ugly, too verbose, and difficult to read.
  3. boost::format -- a little more readable then ostringstream IMO, but in my performance benchmarks appears to be even slower then ostringstream, so this is out.

To summarize, I'm not really satisfied with the "standard" options. I'd like something that takes both performance and type safety seriously. What other string formatting options are out there for C++?

share|improve this question
    
What's the nature of your output? You might have to roll your own sprintf wrapper if you want type safety. –  Karl Bielefeldt Dec 21 '11 at 17:24
    
Couldn't you just search for sprintf in your code, and review every use carefully? –  David Thornley Dec 21 '11 at 17:40
    
Echoing @KarlBielefeldt - what is your specific use case? If logging - pantheios.org may help some. If something else - perhaps more details will lead to a better set of answers... –  sdg Dec 21 '11 at 17:44
1  
I haven't tried it personally, but take a look at SFIO (Safe, Fast I/O library for C). www2.research.att.com/~gsf/download –  Aidan Cully Dec 21 '11 at 17:48
1  
Writing it yourself can be the sensible choice in some cases. If you are only looking for basic string formatting, like int-to-ascii conversions, then it is easy to write a snippet that is approximately 100 times more effective than sprintf, both in terms of speed and memory consumption. The number 100 is based on one of my embedded projects, where I compare my own itoa() version with sprintf. Implementing your own itoa() could perhaps be worth the less than 30 minutes of your time it takes to write that function. Though of course that assumes C strings and it won't have much type safety. –  user29079 Dec 22 '11 at 12:37

5 Answers 5

I recommend this formatting library which I wrote recently. Here is an incomplete list of its features:

  • Format string syntax similar to the one used by str.format in Python.
  • Type safety and support for user-defined types.
  • High speed: performance of the current implementation is close to that of glibc's (s)printf and better than performance of IOStreams. See Speed tests.

It's a new library, but it already supports almost all of the formatting options of printf (with different syntax), in addition to that it supports positional arguments, center alignment, custom fill character and user-defined types.

Update: now it also provides a safe printf implementation

share|improve this answer
1  
Thanks! I actually commented on your blog a while back. Im looking forward to playing with your library. I've also got a lot of ideas based on my work around optimizing string formatting –  Doug T. Dec 30 '12 at 16:35
    
@DougT: Yes, I remember. I just thought that it might be useful for others who come across your question. –  vitaut Dec 30 '12 at 16:57
1  
The library looks comprehensive and robust. +1 –  Yam Marcovic Oct 5 at 16:07
    
Thanks, @YamMarcovic. –  vitaut Oct 5 at 16:14

This is not a complete answer however, i guess, given that performance matters - scaling up sprintf might be a better starting point.

One area where you need to look at is how GCC works. Basically, even though C (and C++) doesn't bother as a language to do typecheck of %d vs. having really integer on the respective arguments, typically GCC always catches that and gives Warnings. You can actually treat Warning as Error with -Werror options. The point is that essentially GCC already does 'type safety' verification at compile time. That is exactly what you need.

share|improve this answer
    
Yeah MSVC does this also, but it doesn't always catch everything. There's still some things that appear to get by. –  Doug T. Dec 21 '11 at 17:38

Streams are very slow because they have a relatively inefficient implementation, and also because they have a whole bunch of overhead bells and whistles that you really don't need. Fundamentally, they serve the exact purpose you need.

The question, ultimately, is about exactly how much effort you're willing to go to and how many types you're outputting. sprintf isn't just unsafe, it's also completely unextendable, something that isn't true of ostringstream. You can also use expression templates to improve it's performance. The performance problem of ostringstream is not endemic to it's design at all.

share|improve this answer

I was pulled here after writing my own printf-like type-safe format helper currently for revision on CR [link]. I was wondering about better alternatives and found myself thinking in too much conceptual way that seems to be more suitable here than in CR.

Type-Safety Problem of snprintf

The n or Microsoft's _s suffix may protect against buffer overflow and many-compiler-built-in-args-check may protect against other errors (like not enough arguments), but still, there are some corner-cases. The problem is in va_list, where all the types are erased and casting is performend based on type-specifiers inside format string. Other problem is that you cannot pass objects (non-trivially-copyable classes and even struct/POD wrappers are a problem). It is not about type-safety but about ease of usage.

Alternatives to va_list

Variadic templates are the solution and can be used to produce really fast formatters. One other thing I currently have in my mind is to use new C++11 literals, e.g. operator "" _fmt(const char *str, size_t len) which could check for specific formatting options and select the fastest implementation (especially when positional arguments are not used). C++14 further removed the need for one-return-statement constexpr functions, that this can be done in more elegant way.

This buf << "hello %s! pi = %g :)"_fmt("world", 3.14159265) could be the final form for fast and type-safe alternative I have in mind. It could be made really-really fast with few template specializations.

Boost::format and ostream

Both are monstrous inside, boost::format even more, but are type-safe, extensible and with few more tricks involving variadic templates and specializations, it could be made faster. How did you benchmarked them? snprintf is for buffers, ostream is for streams, ostringstream for strings, which is more complex. The idea behind is probably to make something universal and working, that would serve the purpose. The speed is usually not that critical these days, algorithm selection (e.g. O(n^2) vs. O(n log n)) is often more important than how long O(1) will really take.

Fast vs. universal

The fastest solution would always be to write your own specialized version for each (kind of) format string. Nothing can beat that. So, the question is, how close/far you want to go?

I am a firmware programmer and IAR EWARM is offering options about prinf and scanf implementation - usually some basic (e.g. no hex-floats) vs. full. This clearly is about choosing the power vs. speed (and size).

share|improve this answer

I suspect you are looking for a silver bullet. It's really is a triangle, (fast, powerful, safe). You need fast, so your only choice is powerful or safe, you cannot have both. sprintf is fast and powerful, at the expense of safety.

You should be able to wrap sprintf in ways that restrict it's use (making it less powerful, more safe), and though run-time checks and rigorous code review, ensure your performance and safety targets are met. If this cannot be achieved, think carefully why not before choosing another option.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.