Tuesday, March 27, 2012

C versus C++ performance: printing and string conversions

A widely held belief is that C++ code is inherently slower than C code. Although this is true sometimes, it is usually largely a myth. In fact, there are situations in which the opposite holds true: C++ is faster than C.

Ironically, C++ is faster in one of the instances where people typically expect the opposite: printing with C++'s iostream library versus C's stdio library.

Using Microsoft Visual C++ 2010, I tested printing "Hello World!" a million times to a file using ofstream and fprintf. Here are the results:

C          C++        Comparison
0.381     0.24       C++ is 60% faster than C

To be fair, this myth problems stems from a very related fact: if we try out the same experiment printing random integers, we get the following:
C          C++        Comparison
0.307     0.929      C is 3 times faster than C++

If you've done conversions between strings and numeric types prior to C++ 11, you've probably suspected that these conversions are not very efficient:

string to_string(int i)
  stringstream ss;
  ss << i;
  return ss.str();

However, there's no reason why iostream can't make full use of C's conversion routines for better efficiency. To see that conversions are really the problem here, let's redo the experiment by first converting the integers into strings using std::to_string, and then printing out the strings with ofstream:

C          C++        Comparison
0.306    0.606       C is 2 times faster than C++

Yes, this actually means that:
cout << to_string(42);
is faster than:
cout << 42;

This is obviously a design flaw in the Microsoft's C++ implemention (which is otherwise an excellent C++ compiler), as we could get a better implementation by simply changing the library:

ostream& operator<<(ostream& os, int i)
  // Replace current code with:
  os << std::to_string(i); // use std::string overload; also note that to_string never throws here

In fact, converting it to a std::string and then printing has some overhead of its own (probably very little due to the small string optimization), but we can get closer to C conversion performance using sprintf to convert the integer into a C string buffer (its easy to calculate the maximal length of the array using log, sizeof and adding 2 more chars, one for the potential minus sign and one for null terminating the string):
With this, we get down from 0.606 to 0.5 seconds. There's still a gap of 64% in performance, which is unexplained for. What it does mean, however, is that Microsoft's C++ library did not prioritize efficient type conversions to strings, which does happen quite a lot when parsing.

C++ prints faster than C.
C converts numeric types to strings faster than C++.
There's no reason why C++ should convert slower than C, as it has full access to C's underlying implementation of the stdio library (it's included in C++ too, after all).

No comments:

Post a Comment