208 lines
7.1 KiB
Markdown
208 lines
7.1 KiB
Markdown
# C Musings
|
|
|
|
Some musings on C-family languages, by Nora for Ania!
|
|
|
|
## History of the C Family
|
|
|
|
In the early days of computing, MIT, General Electric, and Bell Labs created MULITCS,
|
|
the Multiplexed Information and Computing Service. This operating system introduced
|
|
many ideas that are commonplace today. It also kind of sucked, and the project fell apart.
|
|
|
|
From the ashes rose UNIX, an operating system which, like all OSes at the time, was written
|
|
entirely in non-portable assembly code for a specific machine, the DEC PDP-10. It used
|
|
an interpreted language called B for some non-performance-critical code that needed to be
|
|
easy to modify.
|
|
|
|
As it became popular in the early 1970s, Dennis Ritchie, Brian Kernighan, and others decided
|
|
to port it to a number of other computers. To ease this task, they invented a computer language
|
|
that abstracted over the specifics of machine language of any particular computer, but was
|
|
close enough to the model exposed by most machines that, with a little machine-specific
|
|
assembly code, the only thing that had to be ported to each new machine was the compiler.
|
|
|
|
The compiler is a "simple" piece of code that translates the C code to machine-specific
|
|
instructions. Nowadays, compilers are extremely complex, as they perform optimization as
|
|
well as simple compilation.
|
|
|
|
Because C is so low level, it is entirely _imperative_. All of its high-level features,
|
|
such as structures and function pointers, come from the way the machine works, not from
|
|
any magic (runtime) applied by the compiler.
|
|
|
|
### C++
|
|
|
|
C++ is an invention of Bjarne Stroustroup, a brilliant computer scientist who decided to
|
|
apply object oriented principles to C. The result was an absolute mess of a language
|
|
that is nonetheless very powerful and, as time goes on, is becoming more and more safe
|
|
and easy to use.
|
|
|
|
It has somewhat more of a runtime then C, and the compiler does a lot more work, including
|
|
permitting type-system level templating.
|
|
|
|
### C#
|
|
|
|
C# is Microsoft's answer to Java. It's really similar to Java and has very little to do
|
|
with C.
|
|
|
|
## The C Programming Language
|
|
|
|
That's the name of a [terrible book](https://www.amazon.com/Programming-Language-2nd-Brian-Kernighan/dp/0131103628)
|
|
that you shouldn't read. I did, it blew my mind and I learned nothing.
|
|
|
|
Anyway, what defines the C language?
|
|
|
|
C is **statically typed**. That means, like Java and unlike Python, a variable has to
|
|
keep the same type throughout the program:
|
|
|
|
```c
|
|
int a = 24;
|
|
a = "Hello, world!"; // Compiler error
|
|
```
|
|
|
|
C is **weakly typed**. That means, unlike both Java and Python, C will do it's _very best_
|
|
to do _something_ even when you give it types that make little sense, _based on the way
|
|
the PDP-10 would have done it in its CPU_.
|
|
|
|
```c
|
|
int a = 25;
|
|
char b = 'b';
|
|
a + b; // This is an integer of the value 25 plus the integer value of the letter b.
|
|
```
|
|
|
|
C is **procedural**. Its primary abstraction is the procedure call, or function call.
|
|
This is as opposed to object-oriented languages, for example.
|
|
|
|
Finally, C is **memory unsafe**. Because it has no runtime and gives you access to the
|
|
very lowest level of the machine (or at least does a good job of pretending), you can
|
|
do silly things without anyone stopping you.
|
|
|
|
```c
|
|
char[] c = "Hello, world!"; // A string is an array of characters.
|
|
char nonsense = c[134]; // This will cause a problem, probably.
|
|
```
|
|
|
|
This code won't throw an `IndexOutOfBounds` exception or anything; there's no runtime
|
|
to check that. Instead, the compiler will very earnestly try to write code that does this;
|
|
it will get the address of the start of the array `c`, compute the memory address 134 bytes
|
|
later, and try to see what's there. This will certainly be gibberish and might cause the
|
|
operating system to kill your program.
|
|
|
|
# Setting Up a Development Environment
|
|
|
|
To develop C, you need a _compiler_, and it's nice to have a _build system_. I'll assume
|
|
you're on Ubuntu; to install GCC, the GNU Compiler Collection, and make, a build system,
|
|
on Ubuntu, run:
|
|
|
|
```bash
|
|
sudo apt install gcc make
|
|
```
|
|
|
|
Now make a directory to work in and open up a file. I'm going to call it `00-helloworld.c`.
|
|
Into that file, type:
|
|
|
|
```c
|
|
#include <stdio.h>
|
|
|
|
int main(int argc, char** argv) {
|
|
printf("Hello, world!\n");
|
|
}
|
|
```
|
|
|
|
(I'll explain it all in a sec!)
|
|
|
|
Now, in the terminal, in that folder, type:
|
|
|
|
```bash
|
|
# GCC, please compile the code in 00-helloworld.c
|
|
# and write the executable out to 00-helloworld.64
|
|
gcc 00-helloworld.c -o 00-helloworld.64
|
|
```
|
|
|
|
This should print out "Hello, world!" in your terminal. Let's dissect that.
|
|
|
|
```c
|
|
#include <stdio.h>
|
|
```
|
|
|
|
Beginning with `#` means that this is a preprocessor directive, telling the compiler
|
|
to look up and include a file called `stdio.h` in the standard search path (because of
|
|
the `<` and `>`, as opposed to `"` and `"` which mean look in the current directory)
|
|
and include its text here.
|
|
|
|
That file defines, among other things, the function `printf` that is used later.
|
|
|
|
```c
|
|
int main(int argc, char** argv) {
|
|
```
|
|
|
|
This is the definition of the magic function `main`, which is run when the program starts.
|
|
It returns an `int`, which should be zero for success or anything else for failure, and
|
|
takes the number of command line arguments `argc` and an array of arrays of characters
|
|
(an array of strings) `argv`. `c` stands for "count" and `v` for "vector" in this case.
|
|
|
|
```c
|
|
printf("Hello, world!\n");
|
|
```
|
|
|
|
This calls the `printf` function, which `print`s a `f`ormatted string, although we're
|
|
not using any of the formatting options here. The `\n` is a standin for the newline
|
|
character.
|
|
|
|
Congratulations! This is your first C program, and demonstrates that your development
|
|
environment is working.
|
|
|
|
# Pointers and Looping
|
|
|
|
In a file called `01-arguments.c`, write:
|
|
|
|
```c
|
|
#include <stdio.h>
|
|
|
|
int main(int argc, char** argv) {
|
|
printf("Given %d arguments.\n", argc);
|
|
|
|
int index = 0;
|
|
while (index < argc) {
|
|
printf("Argument %d: %s\n", index, argv[index]);
|
|
index = index + 1;
|
|
}
|
|
}
|
|
```
|
|
|
|
This is pretty similar, but has a few more complications.
|
|
|
|
```c
|
|
printf("Given %d arguments.\n", argc);
|
|
```
|
|
|
|
Here, `%d` means "replace this placeholder with the first argument after the string,
|
|
which should be an integer". `d` stands for digit.
|
|
|
|
```c
|
|
int index = 0;
|
|
```
|
|
|
|
This is the declaration of a variable "index", which will be used to keep track of our
|
|
place in the array.
|
|
|
|
```c
|
|
while (index < argc) {
|
|
```
|
|
|
|
This means run the following code until the `index` variable becomes greater than or equal
|
|
to `argc`, the number of command line arguments.
|
|
|
|
```c
|
|
printf("Argument %d: %s\n", index, argv[index]);
|
|
```
|
|
|
|
This line has a few new things in it; `%s` is the placeholder for strings, and `argv[index]`
|
|
is taking looking at the `index`th element in `argv`, an array of strings.
|
|
|
|
Or, you can look at it a different way: `argv` is a `char**`, a `*` (pointer) to a `*` (pointer)
|
|
to a `char`. A "pointer" is simply an **unsigned integer** which represents, instead of a
|
|
number, a location in memory.
|
|
|
|
So, `char** argv` is the memory location of the first element in a list of pointers, each
|
|
of which is the memory location of the first element in a list of `char`s. Those lists of
|
|
`char`s all end with `\0`, the 0 byte, and represent the text of the program's command
|
|
line arguments.
|