4

Are there any aspects to the C++ programming language where the code is known to be slower than the equivalent C language? Obviously this would be excluding the OO features like virtual functions and vtable features etc.

I am wondering whether, when you are programming in a latency-critical area (and you aren't worried about OO features) whether you could stick with basic C++ or would C be better?

user997112
  • 29,025
  • 43
  • 182
  • 361
  • 1
    Its not the code (which is the same). But the style the code is written in that will make the difference. – Martin York Sep 11 '12 at 21:28
  • I would expect equivalent features in the C and C++ languages to be equally fast. Why shouldn't they be? – john Sep 11 '12 at 21:29
  • Does the standard library count? http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2271.html – Brendan Long Sep 11 '12 at 21:29
  • 1
    This is a good read: [Writing a binary file in C++ very fast](http://stackoverflow.com/questions/11563963/writing-a-binary-file-in-c-very-fast) - a very unexpected result that shows C++ streams being slower than `fwrite()`. – Mysticial Sep 11 '12 at 21:31
  • 1
    This remind me when Linus Torvalds explained why Linux uses C and not C++ http://harmful.cat-v.org/software/c++/linus – André Oriani Sep 11 '12 at 21:32
  • 4
    http://programmers.stackexchange.com/questions/45138/worst-practices-in-c-common-mistakes/45169#45169 – Edward Strange Sep 11 '12 at 21:46

7 Answers7

5

Nothing in the C or C++ language standards specifies the speed of any construct (C++ does specify the time complexity of some operations applied to containers, but that's outside the scope of your question). The speed of the code generated for a given construct depends on the compiler used to compile it, and on the system it runs on.

For a given code construct that's valid C and valid C++ with the same semantics, there's no fundamental reason why either should be faster than the other. But it's likely that one will be faster than the other if the developers of the compiler were a little more clever.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • Thank you, I understand- I guess my question should have coupled the compiler along with the language when I asked as the language is just a portal to producing the assembler. – user997112 Sep 11 '12 at 21:33
  • 2
    @user997112: *"the language is just a portal to producing the assembler"* -- I wouldn't put it that way. A program in a high-level language such as C or C++ specifies *behavior*. Assembly code is just a tool to producing the desired behavior, not an end in itself. – Keith Thompson Sep 11 '12 at 21:35
3

That depends on what you mean by "equivalent". If you compare C's stdio.h with C++'s iostream, stdio.h operations are generally faster (quite a bit faster in some situations). But if you are talking about code written in the subset of C++ that also compiles as valid C, the generated machine code will likely be identical.

Marcelo Cantos
  • 181,030
  • 38
  • 327
  • 365
  • while for printf() vs. cout <<, it's usually the other way round with high optimization levels because of run-time vs. compile-time evaluation of the format string. – mic_e Sep 11 '12 at 22:48
  • 1
    @mic_e: Not in my experience, though I admit that it has been a long time since I've looked at real numbers. Factors to consider: 1) The CPU cost of parsing format strings is negligible, even relative to memory bandwidth, let alone I/O bandwidth. 2) Optimising iostreams is a non-trivial exercise, due to its heavy reliance on fine-grained delegation to virtual member functions of buffer objects (e.g., `basic_streambuf::xsputn`) and the use of facets. – Marcelo Cantos Sep 11 '12 at 23:49
  • FWIW, [Here's](http://www.daniweb.com/software-development/cpp/threads/202238/is-iostream-slower-than-printf) a three-year-old thread with some microbenchmarks that show printf consistently and dramatically outperforming cout. – Marcelo Cantos Sep 11 '12 at 23:50
  • I note that those "benchmarks" don't bother to say `std::ios_base::sync_with_stdio(false);`. When a stream has to interact with stdio at every step along the way, of course it's gonna have some trouble keeping up. – cHao Sep 11 '12 at 23:59
  • 1
    When i say `std::cout.rdbuf()->pubsetbuf(new char[8192], 8192);`, the difference between cout and printf is much, *much* less dramatic (even after calling `std::setvbuf(stdout, NULL, _IOFBF, 8192)` to even things up a bit with stdio). In fact, when outputting text, half the time cout is just a tiny bit *faster* once stuff is in the cache. (374 vs 375 ms) Outputting ints is still slightly slower, but not by much (499 vs 468 ms). – cHao Sep 12 '12 at 01:38
  • 1
    Actually, sync_with_stdio doesn't seem to make near as much difference as the buffering. A buffer as small as 16 bytes significantly beefs up cout (in VS 2010), while the same buffer with stdio actually slows it down (to the point where cout is consistently faster, even outputting ints). Seems stdio's biggest edge is that it has a decent size buffer by default. – cHao Sep 12 '12 at 02:19
  • @cHao: All good points, but your conclusion seems to largely concur with my answer — printf is faster for anything more interesting than a bare string, even after tuning. I also noticed that `sync_with_stdio` seems to be a no-op in VC++. It sets a private static member variable (`_Sync`), but doesn't appear to use it for anything. – Marcelo Cantos Sep 12 '12 at 12:14
  • Yeah...printf seems to be a little bit faster overall. Just not "consistently and dramatically" faster if you do it right. :) The difference is in line with what one might expect from languages both known for their performance. – cHao Sep 12 '12 at 12:37
  • @cHao: Agreed. I should have made it clear that I don't put much stock in microbenchmarks. They merely provided an interesting data point, and a counterpoint to mic_e's suggestion that, "…it's usually the other way round…" – Marcelo Cantos Sep 12 '12 at 12:40
3

For one example, C++ lacks the keyword restrict. Used correctly that sometimes allows the compiler to produce faster code.

  • it's fairly rare in practice to see benefits from restrict, but it happens,
  • there are plenty of occasions when a C++ or C compiler can deduce (after inlining) that the necessary conditions for restrict apply, and act accordingly, even though the keyword isn't used,
  • C++ compilers that are also C compilers might provide restrict or __restrict as an extension anyway.

But occasionally (or quite commonly in some domains), restrict is a really good optimization, which I'm told is one of the reasons for still using Fortran. It's certainly one of the reasons for the strict aliasing rules in both C and C++, which give the same optimization opportunity as restrict for a more limited set of circumstances.

Whether you "count" this depends to an extent what you consider "equivalent code". restrict never changes the meaning of a program that uses it validly -- compilers are free to ignore it. So it's not a stretch to describe the program that uses it (for the eyes of the C compiler) and the program that doesn't (for C++) as "equivalent". The version with restrict took more (perhaps only slightly more) programmer effort to create, since the programmer has to be sure that it's correct before using it.

If you mean, is there a program that is valid C and also valid C++, and has the same meaning in both, but implementations are somehow constrained by the C++ standard to run it slower than C implementations, then I'm pretty sure the answer is "no". If you mean, are there any potential performance tweaks available in standard C but not in standard C++, then the answer is "yes".

Whether you can get any benefit from the tweak is another matter, whether you'd have got more benefit for the same amount of effort with a different optimization available in both languages is another, and whether any benefit is big enough to base your choice of language on is still another. It's laughably easy to interoperate between C and C++ code, so if you have any reason at all to prefer C++, then like any optimization that alters your preferred way of coding, switching to C would normally be something you'd do when your profiler tells you your function is too slow, and not before.

Also, I'm trying to convince myself one way or the other whether the potential for exceptions costs performance, assuming that you never use any type that has a non-trivial destructor. I suspect that in practice it probably can (and that this is a contradiction to the "don't pay for what you don't use" principle), if only because otherwise there'd be no point gcc having -fno-exceptions. C++ implementations bring the cost down pretty low (and it's mostly in rodata, not code), but that doesn't mean it's zero. Latency-critical code may or may not also be binary-size-critical code.

Again it might depend what you mean by "equivalent" code -- if I have to compile my so-called "standard C++ program" using a non-standard compiler (such as g++ -fno-exceptions) in order to "prove" that the C++ code is as good as the C, then in some sense the C++ standard is costing me something.

Finally, the C++ runtime itself has a start-up cost, which is not necessarily identical to the C runtime start-up cost for the "same" program. You can generally hack about to reduce the cost of both by removing things you don't strictly need. But that is effort, implementations don't necessarily do it for you completely every time, so it's not strictly true that in C++ you don't pay for what you don't use. That's the general principle, but achieving it is a quality of implementation issue.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • +1, you did the best job of actually addressing the issues. – R.. GitHub STOP HELPING ICE Sep 11 '12 at 23:21
  • @R..: cheers. If you have any remarks/corrections/additions on my description of `restrict` then feel free to edit or add them as comments. It's not a section of the C standard that I claim to be able to read without getting a headache, best of three. – Steve Jessop Sep 11 '12 at 23:31
2

Contrary to what many C programmers like to think, one can often write tighter and faster code in C++ all without having to sacrifice a great deal in design.

I can't think of anything in C++ that is slower than its counterpart in C. Virtual functions NOT excluded.

Edward Strange
  • 40,307
  • 7
  • 73
  • 125
1

Does Latency critical mean as fast as possible or does it simply mean that everything has to run in predictable time?

If it is the second case, then the only things that don't run in predictable time are new, delete and try/catch. In embedded programming there are directives to avoid such calls. In other cases, especially in C++11 you might notice some things are faster (std::sort is faster than C's sort() ) and some are marginally slower.

But what you gain over C++ is higher abstraction levels and you don't get the C-style bugs (like the typical malloc() without a corresponding free() )

Grim Fandango
  • 2,296
  • 1
  • 19
  • 27
  • 4
    Right, bugs in C caused by a missing `free()` are just replaced with about 10,000 more ways to introduce a problem. Actually not even replaced since a missing call to `delete` serves just as well. Of course RAII takes care of that... but remember to follow the rule of three! /rant – Ed S. Sep 11 '12 at 21:35
  • Regarding your question, I mean "as fast as possible" – user997112 Sep 11 '12 at 21:37
  • @user997112: In that case, a typical C++ programming style can often lead you to write faster code with less effort. Since you can get most of your work done without ever calling `new` or `delete`, this means that many of the objects you work are on the stack, hence in the same cache page. This makes your code run orders of magnitude faster. Of course, you can do that in C, but it requires hard work. It's C++ style of code that lets you write code where more objects reside in the stack than in C style of code. – Grim Fandango Sep 11 '12 at 21:49
  • Bjarne Stroustrupp, in this speech, explains how C++11 enables you to write faster code using the style explained: http://channel9.msdn.com/Events/GoingNative/GoingNative-2012/Keynote-Bjarne-Stroustrup-Cpp11-Style – Grim Fandango Sep 11 '12 at 21:53
  • @EdS. Rule of three? What kind of scrub cares about that? We have `unique_ptr` or even `value_ptr`. – Puppy Sep 11 '12 at 21:54
  • @DeadMG: Because everyone can use a C++11 compiler, right? For us to change compilers is a *major* deal which requires all sorts of validation. It isn't worth it for a few nice language features, that kind of thing takes time. It's beside the point anyway; that was just one example of easy C++ makes it to write buggy code. I don't dislike C++, but to say C++ makes it easier to write more robust code than C is a joke. It takes a ton of experience to get to that point in C++, less so in C. It definitely makes some things easier, I love RAII, but it makes other things far more complex. – Ed S. Sep 11 '12 at 22:19
  • @EdS.: You know, RAII is kinda like the opposite of respecting the rule of three explicitly. If you build your classes from lower-level building blocks that respect the rule of three, all other classes built on top of those only need to respect the [rule of *zero*](http://rmartinho.github.com/2012/08/15/rule-of-zero.html). – Xeo Sep 11 '12 at 22:23
  • @Xeo: and the fact that you have to know this stuff illustrates my point beautifully. Again, that was an example. The point is that C++ is a drastically more complicated language than C. I'm not saying it's worse, but it definitely requires a more experienced engineer to write solid code. – Ed S. Sep 11 '12 at 22:26
  • @EdS. There's nothing different between the rule of three and that disgusting goto cleanup stuff, except the rule of three only has to be written once. It's physically impossible to be *less* safe and *less* robust than "Manually remember to clean up exactly the right resources at exactly the right times in every single possible codepath ever or game over". And Rule of Three doesn't require experience, it just requires being told about it. Once. As for not using a C++11 compiler, that's your specific problem, not a general problem. – Puppy Sep 11 '12 at 22:34
  • @DeadMG: I'm not sure why you continue to harp on what was simply an example (I suppose I could have chosen a better one however). There are numerous ways to shoot yourself in the foot in C++ as it is overly complex. I'm in the Torvalds camp on this one, I suppose we just disagree. – Ed S. Sep 11 '12 at 22:44
  • @Ed S. If you "don't dislike C++", then I'm pretty sure you're not in the Torvalds camp. Unless he's changed the rules for getting into the camp since he made his famous post ;-) Anyway, remarks like "what you gain from C++ ..." must be read as, "if you like that sort of thing". For kernel programming often you don't want higher levels of abstraction, and Torvalds criticism seems to be of C++ programmers (he thinks they don't have the discipline to write kernel code) more than of C++. – Steve Jessop Sep 11 '12 at 23:26
  • @SteveJessop: That's true, Torvalds is more vehement on the subject than I am. I *prefer* C (I also work in a systems group, so I have some similar experiences, though obviously not nearly as many). – Ed S. Sep 11 '12 at 23:34
0

There is no code in C++ whose direct equivalent in C is faster- or, indeed, more maintainable.

Puppy
  • 144,682
  • 38
  • 256
  • 465
0

If you're using the language that's the intersection of C and C++, then any difference in performance when compiling that code with a C compiler versus a C++ compiler is purely a quality-of-implementation issue; there's no reason one should be faster than the other.

Of course in the real world, if you're using C++ you program using both the additional features that C++ has over the intersection of C and C++ and using different idioms than you would in C. And conversely, if you're using C, you at least use very different idioms from what you would use in C++, and you may also be using additional features of the modern C language which C++ does not have, like, as Steve mentioned, the restrict keyword, or VLAs or pointer-to-VLA types, or compound literals. These features could give major performance benefits in some situations, but in my experience they're not the reasons most people who choose C over C++ do so.

In my mind, the main difference really is idioms. In C, it's idiomatic to make a linked list by putting the next/prev pointers directly in the structure that's being kept in a list, rather than using a separate wrapper object for the list and list nodes. In C, it's idiomatic to iterate directly over the elements of a string as a character array. In C, it's idiomatic to work with objects that exist entirely in automatic storage whenever possible rather than allocating dynamic storage. And so on. These idiomatic differences are the main ways C code tends to be faster and lighter than C++.

Of course if you want, you can use the same idioms in C++, since most of the language constructs needed for most C idioms exist in the intersection of C and C++. And then you can also use the additional features of C++ when appropriate. But you'll be writing non-idiomatic C++ code, and you might receive a lot of criticism from other C++ programmers...

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711