embedded software boot camp

C: The Immortal Programming Language

Thursday, February 22nd, 2018 by Michael Barr

Barr Group’s 2018 Embedded Systems Safety & Security Survey is now closed and I am in the midst of analyzing the data. This year a portion of my analysis is focused on multi-year trends. One trend that really stands out to me is that the C programming language refuses to give up the ghost.

A longitudinal study of survey data spanning almost a decade and a half shows that C remains the primary programming language of embedded software. Remarkably, in that time C has actually gained market share from 50% to about 70%–at the expense of assembly, C++, and Java.

The graph below shows the relevant data from 2005 through 2018. The first decade of this data is drawn from annual surveys published by the publishers of Embedded.com with the most recent data coming from Barr Group’s annual survey. Each of these surveys of embedded systems designers phrased the relevant question similarly, either “My current embedded project is programmed mostly in [pick one]” or “What is the primary programming language for your current project? [pick one]”.

Language Use Trend Plot

It makes total sense that the use of assembly language as a primary programming language is falling. The last time I wrote an embedded program mostly in assembly was about twenty years ago. Of course, there will always be some low level code that needs to be written in the native language of the machine–if only to bring up the higher-level language execution and for drivers and kernel code. But with inexpensive (and mostly 32-bit ARM-based) microcontrollers increasingly at the heart of our systems there’s no sense wasting time coding the application code in assembly.

We can attribute about 7 percentage points of the growth in use of C to the reduction in use of assembly during these years. This trend has helped use of C grow to about 60%.

But what’s also been happening in this time is that C++ has failed to capitalize on earlier gains. The peak year for C++ use was apparently 2006, when it had 33% share. Use of C++ as the primary language has since fallen and thus added about 10 percentage points to use of C.

I didn’t include Java in the graph, but it’s use has been less common than assembly in every survey year, with high points of 3% and now down around 1% the last three years. And no other language has emerged to maintain greater than 1% share.

What I make of all of this is that C remains the most cost-effective way to write embedded software. In hindsight, object-oriented languages have been tried but failed to establish their value to most programmers. C++ is a player but looks unlikely to ever eclipse its namesake.

What do you see in the data?

Tags: , , ,

21 Responses to “C: The Immortal Programming Language”

  1. Andrew Mellinger says:

    Thanks for doing this survey! I am always interested on how these things change over time. However, I was surprised that you suddenly jumprf to “What I make of all of this is that C remains the most cost-effective way to write embedded software.” Can you show your data that talks about cost and effectiveness? How do you rate effectiveness? I’d like to see the trends of C vs. C++ vs. Assembly on these scales. I ask because many time we chose languages based on constraints that are not about cost or effectiveness. Can you please substantiate that claim? Thanks. -Andrew

  2. andre says:

    I wouldn’t call c++ an “object oriented language” unless you meant it in the pejorative sense.

    C stays where it is because for the most part, it’s predictable and has few dependencies compared to c++… maybe some day Rust will take its place, who knows…

  3. Observer says:

    Excellent article, thanks. I’m looking for some advice 🙂
    I’ve worked with Arduinos about ~1 year (multi-node nRF24, HC05, MPU6050 and stuff). Then I’ve learned about Arm Cortex M with two online courses (busy-wait and interrupts, Timers, UART, SSI, ADC, DAC, designed a game (space invaders), connected to net server via ESP8266)
    I found out that my knowledge of C is limited. What’s the next step for me? I’m a controls engineer (EE) and my language proficiency is like MATLAB > Java > C > C++ (I barely know it)…
    I know I should learn C properly. But what about a higher level language? Nobody seems to like/advertise Java… So I should also learn C++ alongside C…But there is also Rust in the options and everyone is saying it has a bright future and C++ is a mess…I’m quite confused at the moment :\
    My interest is in Robotics, Control Systems and Motion Control
    I’d be grateful if someone could share his/her vision/experience with me. Thanks

  4. James Horton PE says:

    C is, was and shall ever be. If you remove the ‘hype’ and media buzz, there is simply no other language that has
    the diverse utility and control C yields. Embedded dominance is natural for C. Even in clusters, we are dicovering
    that small, concise processor kernels and diverse frameworks are all possible with C. Look for ‘Uni-kernels’ for
    clustsers to become embedded C engines…..

    Only a few can ‘C’ forever, but they will dominate, particularly with robust security.

    sincerely,
    James Horton PE

  5. Chris says:

    Any thoughts on the possibility that Rust could take over off in the embedded world notably thanks to it being both a system level language and its inherent safety?

    • Odin Holmes says:

      Rust is one of the few languages which does not ‘hard code’ things like threading model or memory management into the language, which makes it a viable player. On the other hand on the bare metal/resource constrained end I don’t know that the borrow checker is as useful as it might initially seem as there is a lot less if any, heap use.
      In my work I use C++, at the end of the day I have a pretty good idea of what the assembler should look like, I don’t want to write in assembler because no one else can read it and I will just shoot myself in the foot all day. In C++ I can use the type system to keep myself from all that foot shooting and at zero cost, in rust, I don’t see the same modeling power which C++ expression templates give me. I must admit its been a while since I have looked at rust so it may be in there by now.
      I hope that, as an industry, we move towards safer languages, they only cost more if you do it wrong 😉

  6. Odin Holmes says:

    I have found a growing list of reasons that C++ has had trouble breaking into this domain. The ’embedded’ domain is by no means homogenous and spans a lot of space. In the portion which can assume endless RAM or only requires not leaking resources when out of memory I think C++ is very much the right tool for the job and adoption is all about marketing/bias/legacy stuff. In systems which are memory constrained, hard realtime or where failure is not an option because there is no reporting path to the user we still have homework to do. Exceptions for example often require more RAM when turned on than many chips have, which is obviously a show stopper. There are also a number of things in the standard library or even in the implementation of the core language which do not play well with interrupt service routines.
    We are working on these issues in the committee but I must concede that the critique of C++ being a language which can bite you in unexpected ways in this domain is somewhat understandable. As an example function statics, as in static variables in the body of a function, are guaranteed to be initialized once upon the first call to the function (as of C++11). The following use case however:
    void f(){
    static const my_class = my_factory();
    //use of mc_class here
    }
    where f() can be called from multiple interrupt contexts (e.g. main thread and an ISR or two differen ISR priorities) then there is essentially no way of enforcing that my_factory only runs once without disabling ISRs which causes unexpected jitter.
    The above example is probably not going to be a problem for 99.9% of all programs but it is still theoretically possible. If one purges the language and standard library of all functionality which may not work or have surprising results in the presence of ISRs you basically get this proposal http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3256.html which strips everything down to a small portion of the language. Weighed against the cost of change this may not be worth the effort.

    That being said the real advantage of C++ is its powerfull abstraction capabilities. Jus tbecaus efew current libraries are usable in this domain currently does not mean that we can’t write any. Where C has not changed much since my birth, and therefore there has been little change in the way we code microconzrollers in C since my birth I see huge potential for C++ abstractions and the new paradigms which they allow.

  7. Matt Chernosky says:

    Thanks for this! It’s interesting to see (though not surprising to me) that C++ hasn’t managed to catch on.

    C++ can be pretty hard to learn and if you’re coming from C — as most embedded developers would — not only do you need to learn about object-orientation, but you still get all the “fun” of managing your own memory. Then there is the whole issue of understanding the performance implications of C++ (which embedded developers also seem to stress over) although I’m not convinced everyone with these 32-bit ARMS should be *quite* so concerned. Then there is templating — which probabaly seems pretty foreign — the complexity of keeping up with all the C++ versions. All this is a recipe for fear, uncertainty and doubt.

    Oh, and I haven’t seen too many embedded vendors with C++ example projects ready to go out-of-the-box. If you’re going to use C++ you probably need to buy something or know how to set up the runtime by yourself.

    Don’t get me wrong I think C++ could be great, but I get the reluctance to adopt it.

    I definitely see the longer-term threat to C in terms of safety and security though. How many buffer overflow or use-after-free errors do we need to ship before the business case starts demanding that we don’t let them happen in the first place? Maybe it’ll even be government regulation.

    “Modern” C++ (11, 14, 17) I suspect is one path, although from this data it doesn’t look like developers are going to do it on their own.

    Rust is another intriguing option, especially for bare-metal embedded application, because has no runtime that needs to be set up for each processor type. But it’s pretty tough to learn too.

    • The runtime is not so hard to get set up, but as you mention there are no good examples out there at the moment. I’m working on fixing that part 🙂

      • mollers says:

        >> I definitely see the longer-term threat to C in terms of safety and security though

        Not if you use a reduced instruction-set C coding standard as advocated by Les Hatton and embodied by, for example, MISRA.
        You should also bolster the compiler with static analysis.

  8. Kamil Szczygieł says:

    Just to add another “pro-C++” opinion here I wanted to mention that I wrote a C++ RTOS for microcontrollers (ARM Cortex-M) – it utilizes most of the nice C++11 features like constexpr constructors (e.g. for mutex) or variadic templates (e.g. for safely passing any number of arguments of any type to a thread or software timer). And all of that does _not_ require use of heap – you can use static allocation in every case.

    It is working correctly in several commercial projects – it’s not just a programming exercise or a “proof of concept” (;

    As I’m using C++11 for embedded projects since the time it was still called C++0x I think I can add an opinion, that the experience is both easier (polymorphism, RAII, type safety, better expressiveness, less boiler-plate, …) and more challenging (designing proper object-oriented architecture instead of the usual mess you see) at the same time. The learning curve is very steep and it took me some time to “take off” with everything (mainly to shift my way of thinking), but once this was done I never felt the need to go back to C – even for projects which needed to be small (like a bootloader). After all – even if you just compile your “C-like” code in C++ compiler you can get the the several important C++ features for free – like RAII and stronger type checking – so a clean case for me.

    • Petr says:

      How does ARM C-runtime perform if:
      1) the mutex has constexpr constructor initializing fields to non-zeros and
      2) the mutex is embedded by user to a larger structure that is global variable?

      On AVR the avr-libc would place the structure to .data section and on startup it will copy the the initialization bytes from flash to ram to the variable’s location. GCC on ARM might work differently differently.
      If the mutex were to be initialized by zeros (or by non-constexpr ctor), the user’s structure will in .bss section and will not occupy any flash space.

      I am skeptical about OO architecture, though an architecture is good thing.

      • Kamil Szczygieł says:

        A bit late for a reply, but better late than never (;

        Just as in any other implementation, the object will be in .data and copied from flash during libc initialization. You cannot do that any other way (; For AVR maybe this is a problem, but please bear in mind that for a typical ARM microcontroller in which you intend to use RTOS and C++, you probably have a lot of flash anyway. You don’t employ RTOS for trivial tasks, so usually flash is not a concern and you have at least 128 kB, which is quite a lot.

        If this bothers you, there’s not problem in using “placement new” to initialize the object whenever you need it – it will be in .bss then. Or dynamic allocation, or stack objects + global pointers, or even something else. However you then loose the most important aspect of constexpr constructor – that (from user’s perspective) the mutex (or some other object) is initialized for sure, even when you have 10 threads already running before entering main(). Without that guarantee you must manually and carefully perform such initialization, which will use flash too.

        • Petr says:

          You are right that using placement new (or one of the other solutions you mention) will indeed allow linker to place such global variable to bss. What I have in mind is that a mutex can be usually designed in a way that its fully initialized state is all zeroes. E.g. zero in an owning_thread_ptr field means the mutex is available, zero in recursions_count field meaning no recursion in progress and so on.

          That way the user would have a fully initialized mutex for sure, even when threads are running before main(), with no manual initialization. It can be pleasant to use and still be efficient.

          Having 128 kB is relative – for some it is huge, for some it is not enough. And some people want to use smaller devices. Still, it would be a shame to need more resources than needed.

  9. Grit says:

    I’ve always kind of wished ADA would take off.

    Having the ability to define types with limits at compile time alone makes me want to learn it.
    Not to mention the apparent safety it provides.

    It is my opinion that ARM’s CMSIS being written in C is a big factor in holding back C++ adoption.
    However, I do think C++ usage will rise significantly as the benefits of open source RTOS’s using C++ start to become obvious.

  10. Greg Willits says:

    I agree that “most cost effective” was a leap. There’s no doubt in my mind there must be far more productive alternatives.

    I wrote a lot of web/server side projects over 15 years in non-Java OO languages, and developed over the past 5 years a reasonably rich networked embedded app in C. Comparatively, it has taken me far, far longer to get stuff done in C. So, cost effective doesn’t ring with me. Perhaps “most effective balance overall” as a result of balancing legacy, control, and space issues–those seem to me to always come up as the key reasons to keep using C.

    One interesting thing about all this for me is that I was assuming I should be moving to C++ if for no other reason than to get some more productive standard libraries. My app is not quite where it can “assume endless RAM” as Odin said, so I’ve been hesitant to switch.

    Coming from higher level languages to C, it surprises me that there haven’t been broader attempts/successes, that I have found, to create de facto standard libraries in C with more utility in the general areas of strings, math, etc., that everybody says “oh, yeah, just go get library X” — like you find with Ruby, Python, and other languages. I suppose that’s a testament to how much of an issue avoiding dependencies and unneeded (space consuming) code is with embedded projects (?).

    Anyway, it is quite interesting that C continues to dominate considering everything that’s “wrong” with it. Since starting work in the embedded realm it has taken all my time to get up to speed on hardware and C (and oodles of network protocols) and become somewhat better at it than just “it works” (thanks in part to many of the articles by the Gurus!). So, I haven’t investigated other languages, but it seems like the embedded realm has been ripe for a long time to have a language revolution. If C is so “popular” (or perhaps just necessary), then maybe instead of trying to offer up something totally different like Rust, something just slightly better than C would be a logical objective. Call it “C-fixed” or something 🙂

    Thanks for the survey and results.

  11. Stephen D says:

    Hi all,
    My $0.02 worth. C endures because as Goldilocks put it, it’s “just right”. Higher level than assembler, improving readability, productivity and software reuse. Much less complex than C++.

    My work is at the bottom end of the microcontroller market, mostly AVR. The projects I work on are generally not complicated enough to warrant taking the object oriented approach. C++ v pointer tables don’t consume a lot of memory but every byte counts when you only have 256-512 to start with.

    Cheers,
    Stephen

  12. Louis says:

    it’s one of those time when the mantra “Keep it simple” shows its strength. C is relatively simple. C++ is over-engineered. Java is useless now that you can run virtual machines and emulators. Also, Python is probably taking away from C++ and Java as well for less performance intensive code.

  13. Thorsten Langenhan says:

    Thanks for the results of the survey. From my point of view it isn’t such a surprise that C is THE language for embedded programming.
    Any kind of newly developed processor is a derivative of something that is already existing in the c compiler universe or it begins with an assembler and then to c compiler.
    Looking at the safety side of development life, (accepted) coding rules must be followed, and C has the most sets: MISRA, JSF++, as well as Michael Barrs contribution. Codecheckers for these rules may be existant, but deeper methods like eg. data flow analysis etc. mainly treat C.
    Another reason is comprehensiveness: if C++ gurus contribute their code to an embedded code pool, most -c-used- programmers might not understand the code, so it cannot be maintained. The code might be very clever done for the function, but maybe it has the same effect as if an ADA adept has done the task.
    My expectation: C will maintain its position for embedded, it is its niche.
    By the way: the even older BASIC is still not dead, see TIOBE.

  14. Lance Harvie says:

    We stick to what we know works and what we’re comfortable with.

    C has not been surpassed as the ideal programming language for embedded systems because of technical reasons i.e. code optimization, code footprint etc. but also for a number of other reasons.

    C++ has a higher learning curve which embedded engineers feel may not be warranted given the ROI in productivity.

    C++ may be overkill for a majority of embedded projects since a large number of embedded project are still 8/16-bit single core projects which may not even require communication protocols.

    Finally, the number of active embedded engineers in the work force cut their teeth on C and hence stick to what they best which gets the job done.

    “If it’s not broke don’t fix it”

Leave a Reply