What makes all the words of a programming language actually do anything? I mean, what's actually happening to make the computer know what all of those words mean? If I verbally tell my my computer to do something, it doesn't do it, because it doesn't understand. So how exactly can these human words written into a language actually cause the computer to do some desirable activity?
Computer programmers write, modify, and test code and scripts that allow computer software and applications to function properly. They turn the designs created by software developers and engineers into instructions that a computer can follow.
It all starts with the CPU or processor. Each processor type has a defined set of instructions it's able to perform. These instructions operate over ones and zeroes, which in turn represent whatever you wish them to: numbers, letters, even the instructions themselves.
At the lowest level, a zero is determined by the presence of a certain voltage (usually near 0V) at a transistor and a 1 is the presence of a different voltage (CPU dependent, say 5V)
The machine instructions themselves are sets of zeroes and ones placed in a special locations called registers in the processor, the processor takes the instruction and its operands from specific locations and performs the operation, placing the result on yet another location, afterwards going to fetch the next instruction and so on and so forth until it runs out of instructions to perform or is turned off.
A simple example. Let's say the machine instruction 001 means add two numbers.
Then you write a program that adds two numbers, usually like this:
4 + 5
Then you pass this text to a compiler which will generate the adequate machine code for the processor you will run the program on (sidenote, you can compile code to be run in a different processor from the one you are currently running, it's a process called cross compilation and it's useful, for instance, in embedded platforms). Well, the compiler will end up generating, roughly,
001 00000100 00000101
with additional boilerplate machine code to place the 001 instruction in the next instruction register (instruction pointer) and the binary encoded numbers in data registers (or RAM).
The process of generating machine code from structured languages is fairly complex and places limits on how normal these languages can end up looking like. That's why you can't write a program in english, there's too much ambiguity in it for a compiler to be able to generate the proper sequence of zeroes and ones.
The instructions CPUs can execute are fairly basic and simple, addition, division, negation, read from RAM, place in RAM, read from register, and so on.
The next question is, how can these simple instructions over numbers generate all the wonders we see in computing (internet, games, movie players, etc.)?
It basically boils down to the creation of adequate models, for instance a 3D gaming engine has a mathematical model that represents the game world and can calculate the position/collisions of game objects based on it.
These models are built on very many of these small instructions, and here's where high level languages (which are not machine code) really shine because they raise the abstraction level and you can then think closer to the model you want to implement, allowing you to easily reason about things like how to efficiently calculate the next position the soldier is going to be based on the received input from the controller instead of preventing you to reason easily because you are too busy trying not to forget a 0.
A crucial moment occurred with the jump from assembly language (a language very similar to machine code, it was the first programming language and it's CPU specific. Every assembly instruction directly translates into machine code) to C (which is portable among different CPUs and is at a higher level of abstraction than assembly: each line of C code represents many machine code instructions). This was a huge productivity increase for programmers, they no longer had to port programs between different CPUs, and they could think a lot more easily about the underlying models, leading to the continued complexity increase in software we've seen (and even demand) from the 1970s until today.
The pending missing link is how to control what to do with that information and how to receive input from external sources, say displaying images in the screen or writing information to a hard drive, or printing an image on a printer, or receiving keypunches from a keyboard. This is all made possible by the rest of the hardware present in the computer which is controlled in a way similar to that of the CPU, you place data and instructions in certain transistors in the graphic card or the network card or the hard drive or the RAM. The CPU has instructions that will allow it to place some data or instruction into (or read information out of) the proper location of different pieces of hardware.
Another relevant thing to the existence of what we have today is that all modern computers come with big programs called operating systems that manage all the basic stuff like talking to hardware and error handling, like what happens if a program crashes and so on. In addition, many modern programming environments come with a lot of already written code (standard libraries) to handle many basic tasks like drawing on a screen or read a file. This libraries will in turn will ask the operating system to talk to the hardware in its behalf.
If these weren't available, programming would be a very very hard and tedious task as every program you write would have to create again code to draw a single letter on the screen or to read a single bit from each specific type of hard drive, for example.
It seems I got carried away, I hope you understand something out of this :-)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With