15

As far as I know, C is by far the most widely used language for low level stuff such as systems programming and embedded. Sometimes assembly is used, but that's when you really need to be close to the hardware.

My question is why doesn't C have any competitors in low level development? It might be my ignorance, but I'm pretty sure that C is the obvious (or possibly only) choice for low level programming.

This is as opposed to high level development, where there are many competing programming languages to choose from.

How can you explain this?

Aviv Cohn
  • 21,538

8 Answers8

21

Interestingly, I've been doing embedded programming for 13 years: 6 in Ada and 7 in C++.

Anyway, there are a number of factors that make C well-suited for this type of programming:

  • The runtime/standard library required is very small.
  • Manual memory management is very useful when memory is limited.
  • Easy to make deterministic/real time because you don't have to worry about when a garbage collector will run or when an exception will get thrown.
  • Easy to assign a variable to a specific memory address, which is crucial in writing drivers.
  • A lot of existing code available.
Karl Bielefeldt
  • 148,830
9

In the same way today you might think about browser portability/compatibility (will this code run in Opera!?) people back in the day worried about CPU/architecture portability (will this code run on VAX!?).

So every CPU vendor ended up shipping their systems with a C compiler. It was relatively simple to implement, a lot of people knew C, it performed well, and you didn't have to force your platform's developers to dig into the underlying assembly.

Unlike Javascript though, this momentum wasn't "baked in" to the architecture. C ended up gaining momentum because of its relationship with Unix and the efforts that were undergone to make Unix and C portable across CPUs. You can read a lot about this on C's wikipedia page. In short: Unix was one of the first OS's written not in assembly, but in a higher level language, C. Furthermore C developed explicitly out of attempts to port Unix to other architectures. So those lessons learned helped make C a portable systems langauge. Bell labs created the Portable C Compiler or pcc that made it much easier to support many CPU architectures.

Due to explicit efforts to port Unix everywhere -- C got ported everywhere. So the language was one of the first to have low-level portability baked into its bones and popularity and momentum grew from there.

Doug T.
  • 11,737
5

Because C is the lowest level portable language that exists and is widely supported.

I remember ages ago in some demo was a comment:

C is just asm with more macros.

And it's true. C is just high level enough to allow writing portable code, but low level enough that you can see what exactly is going on at the level of bytes in memory when you need it and thus can easily connect it to the few assembly bits that absolutely need to be platform specific. And absolutely nothing happens implicitly so when you write nothing, it will take no cycles, which is important when you are writing performance critical things in internals of operating system, threading library and such.

All other programming languages except assembly are higher level. Which is great for writing applications, but for the system code being able to judge what the compiled code with look like is more important.

C is also the least common denominator. You can call C library from any other language. Other languages have various requirements that make mixing them difficult.

Jan Hudec
  • 18,410
4

To supplement other answers, don't forget that C was written by Bell Labs, largely for the Unix project. Unix itself was rewritten in C the year the language was released. The Unix system tools and libraries were C-based and followed C conventions. In short, C is the official Unix systems language, and today we're all using Unix derivatives (with the exception of the Windows people).

On top of that, anything more high-level than C begins to sacrifice efficiency and programmer freedom for the often commendable goal of safety. For example, try allocating a dynamically-sized block of heap memory in Go. While Go is considered a systems language, it's difficult to do such low-level manipulations in it; you often can't without significant trickery or overhead. Good C programmers are confident in their ability to use the language properly, and don't want to relinquish such complete power and fine-grained control.

Mike
  • 171
  • 2
3

1) ..C is by far the most widely used language for low level.. why?

It is so widely used because of its age. According to Wikipedia - C (programming language) it is 42 years old. It means 42*number_of_programmers man-years of work done. As the C is included in basic programming courses at any serious programming school the number of programmers that can speak C worldwide is very huge and the amount of now available C code is very very huge.

2) ..why doesn't C have any competitors in low level development?..

your claim "doesn't have any competitors" is not true so it does not have any why answer available.

VHDL (start at http://en.wikipedia.org/wiki/Vhdl) is low level language much more efficient for low level stuff. e.g. for expressing the parallelism that can be compiled directly into hardware circuit design or flashed into and "interpreted" with very high speed and efficiency on Field-programmable gate array (FPGA) hardware chips.

This language is not so wide spread as it is not so old, not usually taught at general purpose programming courses, requires special (though cheap) processors to run on. It is more demanding for programmer's discipline and it is not a language for writing a "hello world" applications that just flashes with few LEDs connected to the COM port or to print some fancy ASCII art tables.

VHDL is serious very strong C competitor for low level development. It is not "just another assembler". It is a paradigm shift


3)

In the category of "least common denominator" languages that might replace C something that would be able to efficiently express/compile into MMIX (pronounced em-mix) is a 64-bit RISC architecture designed by Donald Knuth might becom an competitor.

But!

Who nowadays invests the time and effort into inventing new efficient language with tools etc. writing a compiler for it etc. Who needs such an tremendous effort today? What problems would it solve? Even programmers want to raise children, want to have lives. To make such new language widespread it is not solvable as one-man-show-spare-time-hobby-project anymore. Just compare the code bases of various compilers/IDEs with something you know, something you write yourself - and you'll see another answer to the why

xmojmr
  • 525
2

There are languages competing with C (for low level or system programming): Rust, Cyclone, ... and perhaps Go (which is probably slightly higher level).

And there are more academic languages competing with C.

1

(Source: embedded developer.)

First and foremost, you need a language that compiles to machine instructions, not some intermediate instructions (e.g., Python, Java). If your compiler builds to Java bytecodes, what runs the bytecodes?

The compiled to machine code requirement eliminates many, many high level languages.

Second, your language needs to compile to machine instructions of multiple platforms. OK, so Haskell can compile x86 and ARM. How about the other dozen CPUs out there?

C's linker gives me a crazy amount of power. I can put code in a specific location. Say my CPU starts up at 0x08000. I can tell the linker to store code at that location. I can tell the linker to store certain code in certain segments. The loader will put those segments in a specific location. That's useful if I have code I want to run out of flash vs code to run out of RAM. The Linux kernel puts startup code into a chunk of memory that is later freed, thus recovering memory from code that's only run once, ever.

I can call assembly from C and C from assembly. CPU startup is all in assembly. Low-low level stuff is done in assembly because the C environment might not be initialized yet! (Something has to call main().) The very low level multiple CPU synchronization constructs (semaphores, mutexes, etc) are usually in assembly because they require specific CPU instructions. Caches, MMUs, etc, are usually configured in fiddly bits of assembly. (ARM is loaded with specific instructions to configure cache, MMU.)

C is a thin layer about assembly. C is faster than assembly. So C wins for low level stuff. C wins because no one else has come up with a competitor.

0

Well, the question is what you define as embedded...

Is a Raspberry Pi still an embedded system? If so, then there is competition... You can install Node.JS on it and run JavaScript on it, is it performant? A little bit? Do you care about every circle? (For 10 users (not really)(

So let's say, we only have 33Mhz Do you care about the circles? Yes Likely you could write an Rust - or an Go -Code. But it would give you some cycles tradeoff.. (Security Checks, garbage collection (etc))

Should we care about the GHz or MHz Cycles all the time? Yes and No :)