8

A while back I saw a comment on a Stack Overflow question that surprised me:

No one can write an operating system in C. It is not possible. What one can do is write an operating system in a C-based/C-like language that adds/defines a considerable amount of non-standard capabilities on top of C core.

Is it useful to define C so narrowly? People say Linux, or a GPU driver, or an embedded system was "written in C", not "written in C-with-some-extensions-to-accommodate-the-hardware."

Is it incorrect to do so?

8
  • 12
    People on SO just like to be really technical for no good reason, 90% people will just say that linux is written in C
    – aaronman
    Commented Aug 27, 2013 at 22:23
  • 3
    It is possible to write an OS using "only C" if you use some non-standard compiler features like naked functions, and inline assembly for a few things like hlt. Commented Aug 27, 2013 at 22:29
  • 3
    People wrote OS's in assembly before C came along (and even after). You can write an OS in anything as long as it emits machine code and you can convince the bios that your OS is actually bootable. Supporting hardware is a bit of a different problem ;)
    – Matt D
    Commented Aug 27, 2013 at 23:47
  • 6
    I believe it is possible to write an operating system with a series of 8 donkeys that kick you in the head based on what sounds you make from your perhaps-abused mouth. Commented Aug 31, 2013 at 3:02
  • 10
    @ErikReppen I see no reason to drag Windows ME into this. Commented Aug 31, 2013 at 3:25

5 Answers 5

13

The question is quite broad and as it stands the answer is yes. In fact, the answer is yes for most programming languages but there is a catch.

You need to translate your OS code into something that the machine understands. And it is the machine and its native language and your capability to translate from "your" language to the "native" language that would determine if you can write an operating system in your language or not.

General Theory

Let's say a machine has a lever. And only two things are possible -when the lever is pushed down the machine shall pour coffee and when pulled up the machine shall stop pouring coffee. Now imagine my native language translator is a human who can read C code printed on a paper and decide whether to push the lever up or down. So, for example upon reading the following line our human "compiler-linker" will push the lever down.

printf("pour coffee"); //Support more similar syntax in later versions!

And on reading the following line our human "compiler-linker" will pull the lever up.

printf("stop pouring coffee"); //Support more similar syntax in later versions!

We have successfully written an operating system for this coffee machine entirely in C. For that matter, we can train our compiler to translate Java, C#, KSH, Perl, English, Slavik, Sanskrit etc… and "operate" the machine. Hence the term, Operating System.

Of course most modern computers are capable of doing something more complex than this. And hence the complexity of their instruction set goes beyond just a simple lever state. These instruction sets will ultimately just put some transistors/magnets/LEDs etc. in some state and we humans will interpret that as a result.

The problem hence becomes one of manipulating this machine to achieve the states we want. And if your language (e.g., C) can be translated into that native instruction set and if you can use this bridge to make the machine do what you want then you shall have a successful operating system.

Concrete Example

I am running an x86_64 system right now. This system does not know what C is. It does not know what OS X, Windows, or BSD are. It is ultimately running some x86_64 assembly code. That code was not written by humans (for most part). It was probably written by humans in C or C++ and translated into the assembly language. If I copy this compiled code on to my power PC machine it will not work. I need the original C/C++/whatever_language codebase and I need to translate that code to the power PC language. If I am trying something in C that is not translatable to power PC language then that feature will not work on the new operating system.

What about devices?

The more devices you plug into the machine (e.g., a monitor, a mouse, a printer, an audio output etc.) the more code you will have to write for the bridges. That is what the drivers do. You can write a driver in C if you want. All you need is a way to translate C into the "instruction set" of that device. Usually, it is easier to just embed some code/circuit into the device that reads standard electrical signals and trick the core computer into generating those electrical signals using the standard instruction set and device buses (e.g., USB).

What about bootstrapping?

Now of course, the operating system these days "ships" with the machine. And what people do is just install the code [compiled into the instruction set language of the machine] to some place where the machine can find it on its own. The trick is just to bootstrap the machine to find that code when booting it up. A JVM bootstrap example is below:

public final class Hello {
    public static void main(String[] args_) {
        System.out.println("Hello, World!");
    }
}

0000: cafe babe 0000 002e 001a 0a00 0600 0c09  ................

What about… ?

Please see Tanenbaum or ask another question.

3
  • Good answer, surprised that it doesn't have more up votes :-) Coffee machine example put a smile on my face.
    – CodeART
    Commented Aug 31, 2013 at 20:19
  • Your code example cout << "pour coffee" is C++, not C! Commented Oct 15, 2015 at 5:15
  • 1
    I think this is the best answer, because it shows the entire issue/question is essentially just quibbling. It's more about what an OS is, rather than about capabilities of the C language.
    – Paprik
    Commented Dec 9, 2015 at 10:01
11

If you allow for the possibility of using device drivers (having a C interface) to communicate with the hardware, there's no reason you couldn't write an OS in ANSI C. Anything you might need (like naked pointer) that's not present in ANSI C could be provided by the device driver.

I think the writer of that comment is being pedantic to make a point. He's saying that you can't capture every possible thing that you might need to do in an operating system in the ANSI C language. I'm not sure I agree; ANSI C is a Turing-complete language, and has many low-level constructs including bit twiddling.

In any case, you quoted him out of context. Look at one of the additional comments further down in the thread:

...you're making it sound more drastic than it is. A small amount of assembly language (inline or in separate files) and a good linker are really all you need on most architectures. Other non-standard stuff that kernels use (like fiddling with output sections, packing, alignment, branch-prediction hints, crazy pointer arithmetic, undefined union behaviour) is for optimisation.

10
  • 1
    My intention isn't to snipe at a particular commenter, but to suss out the boundaries of when one can say "X was written in C" and when you really need to say "X was written in a C-like language."
    – Crashworks
    Commented Aug 27, 2013 at 22:56
  • 5
    It's English. You were expecting a hard and fast rule? Commented Aug 27, 2013 at 23:03
  • Wouldn't you need to be able set specific registers and call IRQs to write drivers? I haven't done device drivers for modern PCI bus stuff. Commented Aug 28, 2013 at 1:43
  • @Martin Beckett - I've written embedded systems that used IRQs and specific hardware registers, and that was done in C (mid-90s). As far as I remember there were some extensions involved, but it wasn't a big deal - placing variables at specific addresses, probably a few "intrinsics".
    – user8709
    Commented Aug 31, 2013 at 3:36
  • 3
    @Leushenko: Your comment is both wrong and largely irrelevant. Turing-completeness is a minor point in my answer, but yes, you need a real programming language to do this (HTML is not going to get it done). Yours is the only downvote, BTW. Commented Mar 20, 2015 at 13:53
5

Is it incorrect to do so?

It is not "incorrect" to define C that way ... in a particular context.

My intention isn't to snipe at a particular commenter, but to suss out the boundaries of when one can say "X was written in C" and when you really need to say "X was written in a C-like language."

One can say what one likes! There are no IT terminology laws that say what words mean.

The guy is making a (somewhat pedantic) point by equating "C" with the language that is strictly defined by the ANSI C standards. But that's OK. We know what he means.

And the flips-side is that the rest of us can use "C" to mean practical implementations of the C language ... if we want to.

3

There is one big problem with writing a kernel purely in a high level language: No high level language in existence allows you access to all the CPU instructions that an OS has to use.

Take for example the X86 architecture: It implements virtual memory by providing a single special purpose register which points to a tree of page tables. Now, a kernel that needs to set up the virtual address space for a process needs to do two things: 1. build the tree of page tables, and 2. load a pointer to the root of that tree into the special purpose register. However, that special purpose register is inaccessible from C. Step 1 can be done in C, step 2 can't. - The set of instructions that can come out of a C compiler is a true subset of the available CPU instructions, and that subset lacks all those special purpose instructions that are required to manipulate the processing mode of the CPU itself.

That is why every kernel in existence has to include some amount of assembler code. Of course, kernel programmers try to keep the amount of assembler code as low as possible, writing the bulk of the kernel in a high level language like C. This bulk of code is the reason why people say "Linux is written in C", because 99% of the Linux kernel is indeed C code. But C alone cannot do the trick.

2
  • "There is one big problem with writing a kernel purely in a high level language: No high level language in existence allows you access to all the CPU instructions that an OS has to use." 1) can you back that claim up? 2) in any case, it would the compiler, not the high level language which decides what Instructions are used, so blame it on a compiler, not a language
    – Mawg
    Commented Dec 9, 2015 at 15:08
  • 2
    @Mawg No, I have to blame it on the language: It is the language that does not provide constructs that could be compiled to a load of the cr3 register to change the virtual address space. Compilers cannot use this register for normal purposes, so for the compiler to be able to emit such instructions, you require special language constructs. Intrinsic functions would suffice, but they must be built into the language. As to whether there are languages allowing this: Obviously I don't know all languages out there, but I don't know any that could manipulate the virtual address space. Commented Dec 9, 2015 at 20:54
3

I think that whoever wrote that comment doesn't know what he's talking about because the reason behind C's creation was to write Unix (one of the best operating systems of all time) I'm not saying it's the best language to write an operating system with because many things have changed since the creation of Unix, and now there are many languages that are better than C when it comes to writing an operating system , but it's far from impossible to write an OS with C.

1

Not the answer you're looking for? Browse other questions tagged or ask your own question.