You have written programs in some language: C++, C#, Java or Python. You typed text, pressed run, and something happened. This course is about the part in between: what your computer does with that text. The first step is to separate the text you write from the thing the chip inside the computer follows.
What the processor actually runs
Inside every computer is a chip that does the actual work. It's called the processor, or CPU. It is very fast and very literal. It doesn't understand English, and it doesn't understand C++ or Python either. It understands only numbers. Each small group of numbers tells it to do one tiny thing, like "add these two numbers" or "jump back to an earlier step". A program written as those numbers is called machine code.
Nobody wants to write a game or a banking app as long lists of numbers.
So people write in a programming language instead. The text they write is
called source code. It's ordinary text you can read, kept in a file
such as add.cpp. A program is the whole set of steps a computer
can follow, whichever way it's written down.
To get from readable text to numbers, you need a translator. A compiler is a translating program. It reads all of your source code and writes out the machine code. Here's a one-line piece of C++ that adds two numbers:
int add(int a, int b) { return a + b; }
A compiler called Clang turns it into four numbers: 141, 4, 55, 195. That's when it builds for Linux on the kind of chip in most PCs, with its speed setting turned on. The first three mean "add the two numbers". The last one, 195, means "I'm done, go back". That really is all the processor sees.
The compiler saves the translated program in a file called an executable. That's the file you double-click, or start by name.
Two things follow from this. First, the numbers only mean "add" to one family of chips. A phone or an Apple-silicon Mac has a different family of chip that would read 141, 4, 55, 195 as something else entirely. So a program has to be translated separately for each family. Windows, macOS and Linux also each wrap the numbers in their own kind of file. Second, the chip never runs anything except machine code. Every program you have ever used, in any language, became numbers like these before the chip could follow it.
A program is a set of instructions a computer can follow. A person
writes it as source code: plain text in a programming language,
saved in files such as add.cpp. Source code is written for people to
read and change.
The chip that carries out a program is the processor, also called the CPU (central processing unit). A processor cannot read source code. It reads machine code: a program encoded as numbers, in a format fixed by the processor's family. Each small group of numbers is one simple step, such as "add these two values" or "go back to the step before".
A compiler translates source code into machine code before the
program runs. Here is a real case. The C++ line below defines add,
a piece of code that adds two whole numbers and hands back the result:
int add(int a, int b) { return a + b; }
Clang, a C++ compiler, translates it into four numbers (written here in
ordinary decimal). That is when it builds for Linux on the kind of
processor found in most PCs, with its optimizer switched on (-O1):
141 4 55 195
The first three numbers are one step, "add the two inputs and keep the result". The last number, 195, is the step "go back to whoever asked". The compiler writes the finished machine code into an executable: a file holding a complete machine-code program that the computer's system software (Windows, macOS or Linux) knows how to start.
Two facts follow, and the whole course rests on them:
- Machine code is specific. The four numbers above mean "add" only to one family of processors. A different family (an Apple-silicon Mac, a phone) reads the same numbers as something else, so it needs its own translation. Each system also packages executables its own way, so an executable, as built, targets one processor family and one system. Chapter 1 shows the translators that bend this rule.
- Nothing else runs. However a program was written, the processor ends up following machine code, because that is all it can follow.
Text for people, or numbers for the processor?
Sort each card: is it source code, or machine code?
Loading interactive…
Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.
What this task checks
Structure checked automatically. Whether your ideas are convincing isn't graded, so reread with the checklist.
The compiler says
A model answer
Correct answer
Also accepted:
Why
Why
add.cpp, notes.py) and readable lines like return a + b; are source code. The four numbers and the executables the compiler made (add.exe, sum) are all machine code: numbers meant for the processor, not for you. A file that merely looks scrambled in a text editor need not be machine code: photos and Java .class files look scrambled too.Worked example
Why the PC program won't start on the Mac
-
1
Maya builds
scores.exefromscores.cppon her Windows PC. She copies the executable to her friend's Apple-silicon Mac, and it won't start. -
2
scores.exeholds machine code: numbers in the format of the PC's processor family. The Mac's processor belongs to a different family. The same numbers would mean different steps to it, so it can't follow them. -
3
The executable is also wrapped the way Windows expects. macOS packages programs differently, so it doesn't recognise the file as a program.
-
4
The fix is to copy
scores.cpp, the source code, and compile it on the Mac. The compiler there writes fresh machine code for the Mac's processor in the Mac's format. Source code travels; machine code doesn't.
Worked example
Editing the source, running the old executable
-
1
Sam changes a message in
hello.cppfromHitoHello, saves, and starts thehelloexecutable again. It still printsHi. -
2
The executable is a translation made the last time the compiler ran. Saving the source changed the text file only. Nothing has translated it since.
-
3
The processor runs the executable, so it runs yesterday's translation. After every change to source code, compile again, then run.
Check your understanding (counts toward your progress)
In the machine code 141 4 55 195 for int add(int a, int b) { return a + b; }, what does the last number, 195, tell the processor to do?
Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.
The adding is done by the first three numbers together. 195 is a separate step.
195 isn't data here; it's one step of the program, the processor's code for finishing and going back.
Nothing in add prints. It only adds and hands the result back.
Why
The first three numbers are one step, "add the two inputs". 195 is the step "go back to whoever asked", the machine-code version of return.
The C++ line has two jobs: add, and hand the result back.
What does a processor actually read and obey?
Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.
Source code is text for people. The processor can't read text at all; it needs the translated numbers.
Installing a language gives you a compiler or an interpreter, which are themselves programs. The chip under them still follows only machine code.
Tidied text is still text. The compiler's real job is to turn it into numbers.
Why
A processor follows machine code: a program encoded as numbers in its own family's format. Everything else (C++, Java, Python) has to become machine code, one way or another, before the chip can follow it.
The add example in this section turned one line of C++ into four of something.
Sort each item: can it be used on any computer that has a compiler, or is it tied to one processor family and one system?
Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.
What this task checks
Structure checked automatically. Whether your ideas are convincing isn't graded, so reread with the checklist.
The compiler says
A model answer
Why
Source code can be compiled anywhere a compiler exists. Machine code, and the executables that hold it, are made for one processor family and packaged for one system, which is why downloads come in separate versions.
Correct answer
Also accepted:
Why
Source code travels; what doesn't?
Sort each item: is it source code, or machine code?
Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.
What this task checks
Structure checked automatically. Whether your ideas are convincing isn't graded, so reread with the checklist.
The compiler says
A model answer
Why
Files people write (game.cpp, report.py) and readable lines of a language are source code. The executables the compiler wrote (game.exe, sum) and the four numbers are machine code: numbers for the processor. Looking scrambled in a text editor is not the test, since photos look scrambled too.
Correct answer
Also accepted:
Why
Could a person read it aloud as sensible text?
Practice: Source code, machine code, executables (5 problems · doesn’t affect your progress)
Which of these is an executable?
Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.
.cpp files hold source code, which can't be started directly.
That window starts executables, but it isn't one.
English steps are a plan. An executable holds machine code.
Why
An executable is the compiler's output: a complete machine-code program, packaged so the system can start it.
What does a compiler write when it succeeds?
A file of machine code that the system knows how to start
A friend sends you only tracker.exe and asks you to change one message in it. What do you need from them?
Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.
In a text editor, an executable is scrambled symbols. It's numbers meant for a processor.
Speed has nothing to do with it. You're missing the text to change.
A screenshot shows output, not the code that made it.
Why
You change a program by changing its source and compiling again. An executable is the result, not the recipe.
Which kind of file is meant for people to change?
tracker.cpp, the source code it was compiled from
Put the steps in order, from idea to a running C++ program.
Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.
What this task checks
Structure checked automatically. Whether your ideas are convincing isn't graded, so reread with the checklist.
The compiler says
A model answer
Why
Write, save, translate, write the executable, run. The processor only ever sees the last stage: machine code.
Correct answer
Also accepted:
Why
The compiler can only read a saved file.
Which statement is true of every program you've ever run, whatever language it was written in?
Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.
Python programs aren't. An interpreter carries them out.
No processor reads source code.
Programs are written in many languages; only the machine code at the bottom is common to all.
Why
Whatever the route, the chip follows machine code: either made from your program, or belonging to an interpreter or virtual machine.
What is the only thing a processor can follow?
At the bottom, the processor was following machine code
Clang turned a small C++ function into a few numbers of machine code for a Linux PC. You compile the same C++ for an Apple-silicon Mac. What do you expect?
Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.
Same source, different processor family, so different machine code.
Machine code isn't a reshuffle. Each family has its own format.
Every processor runs machine code. Macs too.
Why
Machine code is in the format of one processor family. The Mac's chip belongs to a different family, so the compiler writes different numbers (§5 shows them).
Is machine code tied to the source, or to the processor?
Different numbers, in the Mac family's own machine code
Compiled, interpreted, and the layer you never saw
If the processor only runs machine code, how did your Python or Java program ever run? It did become machine code. You just never saw it, because a program in between did the work.
If the chip only follows numbers, how did your Python or Java programs ever work? They did get turned into numbers. Some other program just did it for you, out of sight. There are three ways this happens.
C++ (and C and Rust): translate everything first. A compiler reads your whole file and writes out an executable, a file of machine code made from your program. When you run it, the chip follows those numbers directly. Nobody else is involved.
Java and C#: translate halfway, then let a helper finish. The Java or C# compiler translates your code ahead of time, but not into real machine code. It writes bytecode, numbers for an imaginary chip that isn't built anywhere. A helper program called a virtual machine runs that bytecode. The helper is itself ordinary machine code. While your program runs, it rewrites the busiest parts of your bytecode into real machine code (this is called JIT, "just in time", compiling). Those numbers normally live only while the program runs, and you never see them.
Python: a reader that follows along. An interpreter is a program
that reads your program and does what it says, line by line, itself. The
python command is one. It was written in C and compiled long ago into
machine code. When you run your file, the chip is following the
interpreter's numbers, while the interpreter reads your lines. Run the usual
way, your own Python code never becomes machine code of its own.
So whichever language you used, the chip ended up following numbers. But only in C++ are those numbers made from your program and saved in a file you can open. That's why this course uses C++: you can see what your code turned into.
It also explains speed. Python's interpreter has to do a lot of work to perform one line of your code, while a compiled C++ program does that line in a handful of steps.
There are three common routes from source code to the processor.
- Compiled ahead of time (C++, C, Rust). A compiler such as
clang++,g++or Microsoft'scltranslates your source into machine code for one processor family and one system, and writes an executable. When you run it, the processor follows your program's machine code directly. No translator is present at run time. - Compiled to bytecode (Java, C#).
javac(Java) or the C# compiler (run bydotnet build) also translates ahead of time, but into bytecode: numbers for an imaginary processor that doesn't exist as a chip. A virtual machine (the JVM for Java, the .NET runtime for C#) runs it. The virtual machine is itself an ordinary machine-code program. It contains a JIT ("just-in-time") compiler that turns the bytecode into real machine code while the program runs. That machine code normally exists only while the program is running, so you never see it unless you ask the runtime to print it. - Interpreted (Python). An interpreter is a program that reads
another program and carries it out itself, step by step, without first
turning it into machine code of its own. The standard
pythoncommand (CPython) is an interpreter written in C and compiled to machine code. It reads your.pyfile (internally, after a quick conversion to its own bytecode) and does what each line says. The processor runs the interpreter's machine code, not yours. (CPython 3.13 and later include an experimental JIT, but it is off by default.)
So in every case the processor runs machine code. Only on the first route is it the machine code of your program, sitting in a file you can open. That is why this course reads C++: a C++ compiler shows what your code became, with nothing in between.
The routes are also why speeds differ. An interpreter performs many machine-code steps to perform one Python line, and a C++ executable performs a few. A JIT closes much of that gap, but only after running for a while.
Which route is this?
Sort each event into the route it belongs to.
Loading interactive…
Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.
What this task checks
Structure checked automatically. Whether your ideas are convincing isn't graded, so reread with the checklist.
The compiler says
A model answer
Correct answer
Also accepted:
Why
Why
Worked example
Where is the machine code for my Java program?
-
1
A Java programmer runs
javac Add.javaand then looks for machine code. She findsAdd.class. Is that it? -
2
No.
Add.classholds bytecode: numbers for the Java virtual machine, which is an imaginary processor. No real chip follows them. -
3
When she runs
java Add, the JVM (an ordinary machine-code program) starts. It readsAdd.class, and its JIT compiler turns busy parts into real machine code while the program runs. -
4
That real machine code exists only during the run and is never saved anywhere she could open it. The C++ route, by contrast, saves your program's machine code in the executable, ready to read. That difference is what this course uses.
Worked example
Why the same loop is slower in Python
-
1
A loop that adds up the numbers 1 to 10,000,000 takes around a second in Python on a typical laptop, and well under a tenth of a second as compiled C++. Why so much slower?
-
2
In C++, the compiler turned the loop into a handful of machine-code steps per pass. The processor follows those directly.
-
3
In Python, each pass means the interpreter reading what your line asks for, checking what kind of values it has, and then doing the addition. That is a long run of the interpreter's own machine-code steps for every one of your lines.
-
4
Neither language is "wrong". Python trades speed for flexibility. But it shows that how a program becomes machine code changes what the processor does, which is the subject of this whole course.
Check your understanding (counts toward your progress)
What does javac Score.java write into Score.class?
Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.
No real processor follows what's in a .class file. A virtual machine runs it.
It's numbers, not text. The source stays in Score.java.
Nothing has run yet. javac only translates.
Why
javac writes bytecode: numbers for an imaginary processor. The JVM, an ordinary machine-code program, runs it and turns busy parts into real machine code while the program runs.
Java translates halfway before the run.
Which route does the standard python command use to run main.py?
Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.
That's the C++ route. The standard python command never writes an executable of your program.
javac is Java's compiler. It has nothing to do with Python.
A processor can't read text. Something has to stand between main.py and the chip.
Why
python is an interpreter: a machine-code program that reads your file and does what each line says. Your own code never becomes machine code of its own.
Python's route has no separate translation step before the run.
Sort each tool by the route it belongs to.
Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.
What this task checks
Structure checked automatically. Whether your ideas are convincing isn't graded, so reread with the checklist.
The compiler says
A model answer
Why
clang++ and g++ compile C++ straight to machine code. javac and the C# compiler write bytecode, which the JVM or the .NET runtime runs. python is an interpreter.
Correct answer
Also accepted:
Why
Two of these are C++ compilers.
Is the bytecode in a .class file machine code?
Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.
Being numbers isn't enough. Machine code has to be in the format of a real processor family.
javac writes the same bytecode whichever computer it runs on. It isn't for that computer's chip.
Bytecode is numbers, which is why a .class file looks scrambled in a text editor.
Why
Bytecode is numbers, but for the Java virtual machine, an imaginary processor. The JVM (itself machine code) runs it, and its JIT makes real machine code during the run.
Who follows bytecode: a chip, or a program?
Practice: Three routes to the processor (5 problems · doesn’t affect your progress)
What is an interpreter?
Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.
That's a compiler. An interpreter doesn't write your program out as machine code.
That's the processor. An interpreter is a program the processor runs.
It's a program, not a person.
Why
An interpreter reads your program and does what it says. It is itself machine code, which is what the processor actually follows.
The python command is one.
A program that reads another program and carries it out itself
Rust's compiler rustc writes an executable of machine code from main.rs. Which route is that?
Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.
No bytecode or virtual machine is involved; the executable is real machine code.
Nothing reads main.rs while the program runs. It was translated beforehand.
It writes an executable of machine code, which is the first route.
Why
Translating to an executable of machine code before the run is the compiled-ahead route, shared by C++, C and Rust.
An executable of machine code, written before the run.
Compiled ahead to machine code, like C++
Sort each event: does it happen before your program runs, or while it runs?
Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.
What this task checks
Structure checked automatically. Whether your ideas are convincing isn't graded, so reread with the checklist.
The compiler says
A model answer
Why
Compilers like clang++, javac and the C# compiler work before the run. A JIT and an interpreter work during it.
Correct answer
Also accepted:
Why
JIT stands for just in time.
What is the python command itself?
Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.
Something would then have to run that Python program. At the bottom there has to be machine code.
Processors understand only machine code, never a language's text.
Python doesn't use the JVM.
Why
The standard python command (CPython) is written in C and compiled to machine code. That machine code is what the processor follows while your Python runs.
The processor has to be able to follow it directly.
A machine-code program, written in C and compiled long ago
After a C# program finishes, where is the machine code its JIT made?
Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.
That's what the C++ route does. The JIT doesn't save its work for you.
The .cs file is source text, and nothing writes machine code into it.
The bytecode file isn't changed by running it.
Why
The JIT's machine code lives only while the program runs. That's why a C# or Java programmer has never seen their own program's machine code.
JIT machine code is made during the run.
Gone: it existed only while the program ran
Where this goes next
Chapter 1 §1 stacks these ideas into the layers between your C++ and the chip. Chapter 1 §2 runs the compiler one step at a time and shows the file each step writes. Chapter 1 §3 reads the "141 4 55 195" kind of machine code as named steps. Chapter 17 comes back to compilers to show how they choose which machine code to write.