Skip to content

C vs. C++ for embedded development

Tuesday, 7 June 2005  |  alexander neundorf

There is the myth that using C++ per se makes applications and libraries slow and bloated. Avoiding bloat is of special importance for embedded devices, which usually have limited amounts of CPU power and memory. On www.linuxdevices.com I found a short article on this topic: C vs. C++ on Embedded Devices. Let's get down to the statements being made there:

  • C++'s virtues are expensive. Advanced OOP features, such as templates and the practice of using classes in the place of primitives, to name two examples, cause unacceptable code bloat.
    Basically, templates can be seen as glorified macros. So if you are using templates, you should know that each new template instance means generation of code for this type. This is in no way different from using macros in C, except that it is type safe and can be implemented using facilities of the language instead of text processing. So, yes, templates produce code. If you are concerned about the code size, of course you can do your best to avoid code bloat. In many situations it is common practice to implement template classes completely inline in the header. For embedded development, if code size is important enough for you, this is not neccessary. Implement the functions in a foo.inl file, include this in your project and instanciate the templates explicitely: #include template class MyList;
    I don't understand in which way using a class creates overhead. Consider the following example, showing a C++ class Foo and a plain C struct Bar: class Foo { int m_a; int m_b; void doSomething(); }

    struct bar { int a; int b; }

    void do_something_else(); Both versions basically come down to the same: (usually) 8 bytes for the two variables, and a function. More or less the only difference is that void Foo:doSomething() will be name-mangled to a plain C function to something like void Foo_doSomething(Foo* this). So where's the overhead ?

  • A C++ compiler may generate many routines for one function (templates) or create routines where no function explicitly appeared (constructors, casts, etc.). There is generally a one-to-one relationship between a function in C code and the resulting machine-code routine. It's easier to optimize what you can see than what you must infer.
    If you are using C++, you should know the basics of the language. You should know that constructing a variable means that it's ctor will be called. It's the same overhead as calling a init() function in C, except that the ctor can't be forgotten. You should also know that type casts can be functions and operators can be functions. If you are aware of this, there's basically no difference left.
  • Virtual methods and polymorphism complicate runtime linking and require many relocations. This slows C++ application launch time considerably. C applications are both simple to link and amenable to lazy linking, so they load quickly. (For details, see Waldo Bastian's paper ``Making C++ Ready for the Desktop", http://www.suse.de/~bastian/Export/linking.txt.)

    Yes, C++ virtual functions increase startup time due to more symbol lookups during dynamic linking. This is a problem for general-purpose desktop computers. In embedded devices static linking can be a solution. This way dynamic symbol lookup can be avoided.

  • Each class with virtual methods has an associated vtable array, which adds memory overhead.
    Yes, the virtual function tables require memory. But what would you do if you are using C ? Either you would use function pointers (require memory) or you would have to differentiate the function to be called via e.g. type fields and switch statements: switch (foo->type) { case CIRCLE: draw_circle(foo); break; case RECT: draw_rect(foo); break; case POINT: draw_point(foo); break; The other choice for C is the following: foo->fct_pointer=draw_circle; ... foo->fct_pointer(foo); How does this compare to C++ ?
    Option one requires code memory, which could reside in ROM. OTOH it adds runtime overhead since the type of foo has to be checked during runtime and it is vulnerable to coding mistakes. Option two using a function pointer is basically the same as virtual functions in C++ implemented using C. Except that it can't be expressed using built-in facilities of the language it is equivalent to C++.
  • C++'s tighter type-checking makes it difficult to write the space-conscious code reuse common to C applications (think: void *).
    I don't understand this one. You can use void* in C++ too. Usually I only use it for pointers to buffers. What else can you do with void-pointers ?
  • The small, simple code demanded of embedded projects provides maintainability. There is no reason to assume OOP will further simplify such systems. GUIs may not have a simple solution in a rigorous OOP model.
    Well, some people say so, some say different.
  • It's easy to get carried away and start doing OOP for OOP's sake. The One True Object Model may describe a problem perfectly, but it comes at the cost of excessive code. Carefully written C code can be much faster than C++ code, especially on embedded hardware. GTK+'s hand-crafted object system offers much better spatial locality than C++'s more numerous and distributed constructors. Our device has a tiny cache, so locality is an especially important performance consideration.
    Well, and carefully written C++ code can be much faster than (sloppy) C code.

Some things the C++ developer must be aware of:

  • run time type information and dynamic_cast<> add memory and performance overhead, so consider avoiding it
  • creating a variable means that its ctor, i.e. a function will be called
  • AFAIK exceptions still add some overhead using gcc, so it should be considered to avoid them
  • a class without virtual functions is the same as a struct and some functions, memory wise, no additional overhead here, except the implicit this pointer for each member method.
  • be aware how template code generation works. You can reduce this to a minimum if you want to.

And there are also advantages of using C++ for embedded projects:

  • global/static objects will be initialized automatically, when the application starts since then their ctors will be called automatically
  • init-functions can't be forgotten, since ctors are called automatically
  • you have stricter type checking
  • you can write more expressive and concise code, since the language gives you more power
  • use const extensively to make semantics clearer

So, that's about it.
IOW I don't see any inherent disadvantages of C++ compared to C. It boils down to "Know your tools". The best tools are the ones you know best. If you know C++, you know where code is called and where memory is required and can avoid it if neccessary. Additionally you get all the advantages of C++

Alex