14

Almost everyone will now say the blessing:

performance!

Okay, C does allow to write athletic code. But there are other languages that can do so, after all! And the optimising power of modern compilers is awesome. Does C have some advantages that no other language has? Or there's simply no need for more flexible instruments in the domain?

ChrisF
  • 38,948
  • 11
  • 127
  • 168
vines
  • 1,186

8 Answers8

40

Almost everyone will now say the blessing:

performance!

That's part of it; deterministic resource use is important on devices with limited resources to begin with, but there are other reasons.

  1. Direct access to low level hardware API's.
  2. You can find a C compiler for the vast majority of these devices. This is not true for any high level language in my experience.
  3. C (the runtime and your generated executable) is "small". You don't have to load a bunch of stuff into the system to get the code running.
  4. The hardware API/driver(s) will likely be written in C or C++.
Ed Swangren
  • 2,757
18

C was designed to model a CPU, because C was created to make Unix portable across platforms instead of just writing assembly language.

This mean that C programs work well as a programming language for programs that need to have an abstraction level very close to the actual CPU, which is the case for embedded hardware.

Note: C was designed around 1970 and the CPU's were simpler then.

11

One reason for the domination is that it has the right kind of tools for the task. After having developed in embedded platforms in both Java and C/C++, I can tell you that the bare to the bones approach of C++ is just more natural. Saving the developer from feeling that he or she is jumping through hoops because the language is too high level is quite an annoying thing. One good example is the absence of unsigned variables in Java.

And the handy features of VM/interpreted languages are usually not feasible and are left out of the implementation, e.g. Garbage collection.

celebdor
  • 529
10

C requires very little runtime support in and of itself, so the overhead is much lower. You're not spending memory or storage on runtime support, spending time / effort to minimize that support, or having to allow for it in the design of your project.

geekosaur
  • 731
9

As mentioned in other answers, C was developed in the early 1970's to replace assembly language on a minicomputer architecture. Back then, these computers typically cost tens of thousands of dollars, including memory and peripherals.

Nowadays, you can get the same or greater computer power with a 16-bit embedded microcontroller that costs four dollars or less in single quantities -- including built-in RAM and I/O controllers. A 32-bit microcontroller costs maybe a dollar or two more.

When I am programming these little guys, which is what I do 90% of the time when I am not designing the boards they sit on, I like to visualize what the processor is going to be doing. If I could program fast enough in assembler, I would do so.

I don't want all sorts of layers of abstraction. I often debug by stepping through a dissembler listing on the screen. It's a lot easier to do that when you've written the program in C to begin with.

tcrosley
  • 9,621
7

It doesn't entirely dominate as C++ is increasingly being used as compilers have improved and hardware performance has increased. However C is still very popular for a few reasons;

  1. Wide support. Pretty much every chip vendor provides a c compiler and any example code and drivers will likely be written in c. C++ compilers are increasingly common, but not a dead cert for a given chip, and they are often buggier. You also know that any embedded engineer will be able to work in c. It's the lingua franca of the industry.

  2. Performance. Yup, you said it. Performance is still king and in an environment where core routines are still often written in assembler, or at least optimised in c with reference to the assembly output, never underestimate the importance of this. Often embedded targets will be very low cost and have very small memories and few mips.

  3. Size. C++ tends to be larger. Certainly anything using the STL will be larger. Generally both in terms of program size and in memory footprint.

  4. Conservatism. It's a very conservative industry. Partly because the costs of failure are often higher and debugging is often less accessible, partly because it hasn't needed to change. For a small embedded project c does the job well.

Luke Graham
  • 2,403
6

Embedded software is very different.

On a desktop app, abstractions and libraries save you a lot of development time. You have the luxury of throwing another couple megabytes or gigabytes of RAM or some 2+GHz 64-bit CPU cores at a problem, and someone else (users) is paying for that hardware. You may not know what systems the app will run on.

In an embedded project, resources are often very limited. In one project I worked on (PIC 17X-series processors) the hardware had 2Kwords of program memory, 8 levels of (in-hardware) stack and 192 bytes (< 0.2kB) of RAM. Different I/O pins had different capabilities and you configured the hardware as needed by writing to hardware registers. Debugging involves an oscilloscope and logic-analyzer.

In embedded, abstractions often get in the way and would manage (and cost) resources you don't have. E.g. most embedded systems have no file system. Microwave ovens are embedded systems. Car engine controllers. Some electric toothbrushes. Some noise-cancelling headphones.

One very important factor for me in developing embedded systems is knowing and controlling what the code translates to in terms of instructions, resources, memory and execution time. Often the exact sequence of instructions controls e.g. timing for hardware interface waveforms.

Abstractions and behind-the-scenes 'magic' (e.g. a garbage-collector) is great for desktop apps. Garbage-collectors save you a LOT of time chasing down memory leaks, when memory is / can be dynamically allocated.

However in the real-time embedded world we need to know and control how long things take, sometimes down to nanoseconds, and can't throw another couple meg of RAM or a faster CPU at a problem. One simple example: when doing software dimming of LEDs by controlling duty cycle (the CPU had only on/off control of the LEDs), it is NOT OK for the processor to go off and do e.g. garbage collection for 100ms because the display would visibly flash bright or go out.

A more-hypothetical example is an engine controller that directly fires spark-plugs. If that CPU does off and does garbage-collection for 50ms, the engine would cut out for a moment or fire at the wrong crankshaft position, potentially stalling the engine (while passing?) or damaging it mechanically. You could get someone killed.

6

For embedded systems, the big thing is performance. But like you said, why C and not some other performant language?

Many people so far have mentioned availability of compilers, but no one has mentioned availability of developers. A lot more developers already know C than, say, OCaml.

Those are the three biggies.