Eric Day

Thoughts, code, and other oddments.
Dark | Light

< || >

C vs C++

August 11th, 2009

Linux vs FreeBSD, vi vs emacs, MySQL vs PostgreSQL, your habit or favorite technology vs another’s. At the end of the day there is no winner, just a matter of preference for the task at hand. I learned C++ 13 years ago, I forgot most of my C++ knowledge 10 years ago, I discouraged the use of C++ in this period in between, and in the past year I’ve been re-learning C++ (mostly due to Drizzle). So what did I use after unlearning C++ 10 years ago? I wrote everything in C (and by everything I mean this was my performance programming language of choice). This worked quite well, but it’s an interesting evolution that I think is now coming full circle.

When I first started programming C, it was a bit clumsy, and I look back at my old code and cringe. I began to develop a certain programming style that can best be described as object-oriented C programming due to the conventions used. The structs, functions that operated on those structs, and types all were nicely separated into abstract objects. Of course C provides little protection so a user could still poke at what they wanted, but the idea was there and things worked well if you stayed in your sandbox.

As projects became more complex, my C code needed things like inheritance, polymorphism, and templates (although I did not recognize them under those names as I do now). How do you manage such construct in C? There are a few tricks, one being to make your first struct member be a struct of a base class, and cast up/down when switching context. Another trick is to abuse C macros to give you either shared class methods or polymorphism. For example:

#define HASH_ADD(__hash, __key, __obj, __prefix) { \
  if (__hash ## _hash[__key] != NULL) \
    __hash ## _hash[__key]->__prefix ## prev= __obj; \
  __obj->__prefix ## next= __hash ## _hash[__key]; \
  __obj->__prefix ## prev= NULL; \
  __hash ## _hash[__key]= __obj; \
  __hash ## _count++; \
}

This C macro will take any object with the correct data members and treat it like a hash table. There are a few other related macros to manage other hash table operations. I have a similar collection for lists, queues, and other custom objects.

Now, the seasoned C++ programmer will look at these tricks as just say “you’ve created a hacked up limited version of C++ that most people will cringe at”, and I’m starting to agree. It’s time to stop fighting the inevitable. This style of C programming worked very well for me mostly because I was one of just a small handful of programmers that ever looked at this code (most of it never made it open source sadly). Now that I’m working on open source projects and working with developers of all levels, I’m starting to see the value in more common structure and code protections to allow more people to participate easily. A fresh new C++/Java programmer out of college can understand and extend an abstract C++ plugin class more more easy then they can figure out my C macro/casting constructs and work within that framework. Even some experienced C programmers have to take a minute to figure out what I was actually doing (not saying what I was doing was advanced or anything, just more convoluted).

C++ classes scale better than custom C preprocessor macro “languages”. By “scale” I mean ease of developer understanding and use. Ever look at the Zend/PHP header files?

So, what does this mean? I’m starting to understand the value C++ brings, especially in code organization and compile time guarantees. You still get that raw performance if you are careful and test new containers/libraries (for example, stack in the STL does not perform all that well compared to a raw array or even vector). Lately I’ve been working on a few micro (and not so micro) benchmarks seeing what the difference is between C and C++. There is a small price to pay if you start going crazy with inheritance because each new layer adds some constructor/destructor overhead. I avoided this in C by having large objects with everything (and just used casting or macros). Real inheritance makes code much more readable and extensible though.

Three years ago I never would have thought I’d be writing such a blog post, but here I am. This new decision will start trickling into projects I already work in, and new projects will be in C++ if appropriate. Some things will remain i C, but any modular server or application development will probably get switched. I am going to be extremely cautious about performance and will do my best to ensure the move to C++ is not too costly.

Are you offended by this? I’d love to hear your thoughts. Also, think of it this way: at least I didn’t say I’m starting to use Java. :) (Sorry to you Java programmers, I’m just trying to stir up trouble)

Posted in Drizzle, Gearman, Main, MySQL

13 Responses to "C vs C++"

  1. Neil Conway says:

    If the choice is between C++ and a C programming style that involves frequent use of macros like that, then I would probably choose C++ (grudgingly). But I personally find little need for complex macros in the C code that I write or admire (e.g. Postgres uses only a handful of non-trivial macros in 400 KLOC of code). I rarely find the need for complex inheritance hierarchies, for example.

    Certainly C is going to be more verbose and laborious than C++. But given the advantages in simplicity, portability and ubiquity that writing systems software in C yields, I don’t wish for C++ very often.

  2. Andrey Hristov says:

    Eric,
    I share your thoughts. When mysqlnd started it was small thing, then it evolved, kloc by kloc. Now being more than 10kloc. At some point of time I realized that current C structure will crack under its weight, so refactoring was needed and C++ elements were due. Now mysqlnd tries to emulate some object orientation in C. All this could have been easier if it is allowed to have a core PHP extension written in C++. Although, nowadays on every platform you will find a C++ compiler and PHP allows extensions binding to C++ libraries (like RAR). We probably won’t be allowed to switch to C++ for mysqlnd, for the sake of stablity, or maybe if PHP 5.4 comes out
    Best,
    Andrey

  3. Did you find glib provided any alleviation for the pains you were experiencing in C.
    Do you find that STL helped efficiency development once migrating to C++?

  4. Eric Day says:

    Hi Neil,

    Thanks for your comments! Two other factors I did not really emphasize in my post was type safety and code duplication. For example, you can get type-safe code if you create functions for each the various objects you create, but you end up writing the same function multiple times for different types (ie, making objects elements of linked-lists). You can do some tricks by casting or using void pointers, but I like to have those type-safety checks at compile time. This is why I chose the macro way, you get type safety plus no code duplication. You can’t argue the ubiquity of C, but C++ is no stranger. :) Also, as a C programmer, I think the switch to C++ is fairly painless, especially if you already use an object-oriented programming style. I guess we’ll see how things turn out!

    Andrey,

    Yes, I can imagine the headaches trying to plug C++ libraries into PHP extensions, especially given how C/macro oriented the interface is!

  5. Eric Day says:

    Hi Matthew,

    I did not find glib all that useful due to functionality and performance reasons. Some things were ok, but it’s one of those things that is best when you take the full plunge. For example, I don’t like how all types are redefined, this makes mixed applications harder to read since you have competing styles (structs with both guint and uint32_t). Also, I could never take it all since it doesn’t provide the level of functionality I needed.

    With the STL, some things work really well, but others not. For example when I was comparing stack vs vector vs my own array, the STL types did not perform as well. In Drizzle we’ve also had issues with the bitset type. Sometimes this is ok, but there will be cases where these micro optimizations are needed instead.

  6. John Ogle says:

    “A fresh new C++/Java programmer out of college can understand and extend an abstract C++ plugin class more more easy then they can figure out my C macro/casting constructs and work within that framework. Even some experienced C programmers have to take a minute to figure out what I was actually doing (not saying what I was doing was advanced or anything, just more convoluted).”

    This is a true statement, but it could easily be generalized beyond the domain of rookies out of college. I’ve worked with plenty of people in the “field” where if you threw something other than a C# or Java-style language at them they would freeze. This does not make these people bad programmers.

    Anyone that can program could eventually figure out what your C macros are doing, but when does it get to the point that the man-hours used trying to figure them out outweigh the performance increase they give you? This is a question that can only be answered for each project at hand. For something like Drizzle the performance of the application will almost always outweigh the performance of the developer, so a “convoluted” solution that performs better could be the right way to go (provided that it’s been well documented).

    Even Java can be the “right choice” for a software project. If performance isn’t a primary requirement the safety of its sandbox can let you get away with a lot of (stupid) things. The product will be out much quicker due to the programmer not needing to worry about the hardware that their code is running on, and the stupid decisions can always be refactored away down the road.

    This is a great article. Ending the Holy Wars of Software Tools will make this world a better place.

  7. Ben says:

    “…For example, you can get type-safe code if you create functions for each the various objects you create, but you end up writing the same function multiple times for different types…”
    Templates can help out here. You right the function once and at compile time a type specific function is generated for each type you used it with. The built in stl containers (stl::list for a linked list) are template based so you get type safe containers without macros and without duplicating code for each type.

  8. Eric Day says:

    Hi John,

    Excellent points, this shift appeals to not just new programmers, but also to much of the dedicated OO crowd. I think C++ provides a nice balance of structure and performance, so far the overhead has been very minimal.

    Hi Ben,

    Yeah, templates, STL, and base classes will all help with this. The snippet you commented on was about how to accomplish these things in C (which is a bit clunky).

  9. Hi Eric,

    Great article as usual. It is however useless to try to insult us Java programmers. Now that the Java language runs as fast as C/C++ we are all programming in Ruby.

    Cheers, Robert

  10. [...] server in C++ for modularity and future maintenance. I was still going back and forth a bit on the C vs C++ thing, but after people suggested I send some of my C macros to the Obfuscated C Code Contest I [...]

  11. [...] developed primarily in C most of my career, and recently decided to give C++ a shot as my “primary language” due to hacking on Drizzle and MySQL. The [...]

  12. [...] just read an article on C versus C++, you can check it out here. It’s an overview of his programming experiences with C and C++. On many aspects of the [...]

Leave a Reply


< || >
Blog
Wiki
About
Resume
RSS
Comments

E-Mail
Launchpad
LinkedIn
Twitter
identi.ca
Facebook

OpenStack
Scale Stack
Gearman
NW Veg
Veg Food & Fit

Linux On Laptops