diff --git a/c_tutorial.md b/c_tutorial.md index 686583d..9147696 100644 --- a/c_tutorial.md +++ b/c_tutorial.md @@ -163,7 +163,7 @@ Let's quickly mention how you can read and write values in C so that you can beg - `printf("%d ");`: Same as above but without a newline. - `scanf("%d",&x);`: Read a number from input to the variable `x`. Note there has to be `&` in front of `x`. -## Branches and Loops +## Branches and Loops (If, While, For) When creating [algorithms](algorithm.md), it's not enough to just write linear sequences of commands. Two things (called [control structures](control_structure.md)) are very important to have in addition: @@ -200,7 +200,17 @@ X is not greater than 10. And it is also smaller than 5. ``` -A note on **conditions** in C: a condition is just an expression (variables/functions along with arithmetic operators). The expression is evaluated (computed) and the number that is obtained is interpreted as *true* or *false* like this: in C 0 means false and anything non-0 means true. Even comparison operators like `<` and `>` are technically arithmetic, they compare numbers and yield either 1 or 0. +About **conditions** in C: a condition is just an expression (variables/functions along with arithmetic operators). The expression is evaluated (computed) and the number that is obtained is interpreted as *true* or *false* like this: **in C 0 means false, anything else means true**. Even comparison operators like `<` and `>` are technically arithmetic, they compare numbers and yield either 1 or 0. Some operators commonly used in conditions are: + +- `==` (equals): yields 1 if the operands are equal, otherwise 0. +- `!=` (not equal): yields 1 if the operands are NOT equal, otherwise 0. +- `<` (less than): yields 1 if the first operand is smaller than the second, otherwise 0. +- `<=`: yields 1 if the first operand is smaller or equal to the second, otherwise 0. +- `&&` (logical [AND](and.md)): yields 1 if both operands are non-0, otherwise 0. +- `||` (logical [OR](or.md)): yields 1 if at least one operand is non-0, otherwise 0. +- `!` (logical [NOT](not.md)): yields 1 if the operand is 0, otherwise 0. + +E.g. an if statement starting as `if (x == 5 || x == 10)` will be true if `x` is either 5 or 10. Next we have **loops**. There are multiple kinds of loops even though in theory it is enough to only have one kind of loop (there are multiple types out of convenience). The loops in C are: @@ -332,7 +342,7 @@ int main(void) - `scanf("%c",&answer);` reads a single character from input to the `answer` variable. - `if (answer == 'n') break;` is a branch that exits the infinite loop with `break` statement if the answer entered was `n` (*no*). -## Functions +## Functions (Subprograms) Functions are extremely important, no program besides the most primitive ones can be made without them. @@ -492,19 +502,277 @@ Another local variable is `number` -- it is a local variable both in `main` and And a last thing: keep in mind that not every command you write in C program is a function call. E.g. control structures (`if`, `while`, ...) and special commands (`return`, `break`, ...) are not function calls. -## Header Files, Libraries, Compilation +## Additional Details (Global, Switch, Float, Forward Decls, ...) -## Advanced Data Types +We've skipped a lot of details and small tricks for simplicity. Let's go over some of them. Many of the following things are so called [syntactic sugar](sugar.md): convenient syntax shorthands for common operations. -## Macros +Multiple variables can be defined and assigned like this: + +``` +int x = 1, y = 2, z; +``` + +The meaning should be clear, but let's mention that `z` doesn't generally have a defined value here -- it will have a value but you don't know what it is (this may differ between different computers and platforms). See [undefined behavior](undefined_behavior.md). + +The following is a shorthand for using operators: + +``` +x += 1; // same as: x = x + 1; +x -= 10; // same as: x = x - 1; +x *= x + 1; // same as: x = x * (x + 1); +x++; // same as: x = x + 1; +x--; // same as: x = x - 1; +// etc. +``` + +The last two constructs are called **[incrementing](increment.md)** and **[decrementing](decrement.md)**. This just means adding/substracting 1. + +In C there is a pretty unique operator called the **[ternary operator](ternary_operator.md)** (ternary for having three [operands](operand.md)). It can be used in expressions just as any other operators such as `+` or `-`. Its format is: + +``` +CONDITION ? VALUE1 : VALUE2 +``` + +It evaluates the `CONDITION` and if it's true (non-0), this whole expression will have the value of `VALUE1`, otherwise its value will be `VALUE2`. It allows for not using so many `if`s. For example instead of + +``` +if (x >= 10) + x -= 10; +else + x = 10; +``` + +we can write + +``` +x = x >= 10 ? x - 10 : 10; +``` + +**[Global variables](global_variable.md)**: we can create variables even outside function bodies. Recall than variables inside functions are called *local*; variables outside functions are called *global* -- they can basically be accessed from anywhere and can sometimes be useful. For example: + +``` +#include +#include // for rand() + +int money = 0; // total money, global variable + +void printMoney(void) +{ + printf("I currently have $%d.\n",money); +} + +void playLottery(void) +{ + puts("I'm playing lottery."); + + money -= 10; // price of lottery ticket + + if (rand() % 5) + { + money += 100; + puts("I've won!"); + } + else + puts("I've lost!"); + + printMoney(); +} + +void work(void) +{ + puts("I'm going to work :("); + + money += 200; // salary + + printMoney(); +} + +int main() +{ + work(); + playLottery(); + work(); + playLottery(); + + return 0; +} +``` + +In C programs you may encounter a **switch** statement -- it is a control structure similar to a branch `if` which can have more than two branches. It looks like this: + +``` + switch (x) + { + case 0: puts("X is zero. Don't divide by it."); break; + case 69: puts("X is 69, haha."); break; + case 42: puts("X is 42, the answer to everything."); break; + default: printf("I don't know anything about X."); break; + } +``` + +Switch can only compare exact values, it can't e.g. check if a value is greater than something. Each branch starts with the keyword `case`, then the match value follows, then there is a colon (`:`) and the branch commands follow. IMPORTANT: there has to be the `break;` statement at the end of each case branch (we won't go into details). A special branch is the one starting with the word `default` that is executed if no case label was matched. + +Let's also mention some additional data types we can use in programs: + +- `char`: A single text character such as *'a'*, *'G'* or *'_'*. We can assign characters as `char c = 'a';` (single characters are enclosed in apostrophes similarly to how text strings are inside quotes). We can read a character as `c = getchar();` and print it as `putchar(c);`. Special characters that can be used are `\n` (newline) or `\t` (tab). Characters are in fact small numbers (usually with 256 possible values) and can be used basically anywhere a number can be used (for example we can compare characters, e.g. `if (c < 'b') ...`). Later we'll see characters are basic building blocks of text strings. +- `unsigned int`: Integer that can only take positive values or 0 (i.e. no negative values). It can store higher positive values than normal `int` (which is called a *signed int*). +- `long`: Big integer, takes more memory but can store number in the range of at least a few billion. +- `float` and `double`: [Floating point](float.md) number (`double` is bigger and more precise than `float`) -- an approximation of [real numbers](real_number.md), i.e. numbers with a fractional part such as 2.5 or 0.0001. + +In the section about functions we said a function can only call a function that has been defined before it in the source code -- this is because the compiler read the file from start to finish and if you call a function that hasn't been defined yet, it simply doesn't know what to call. But sometimes we need to call a function that will be defined later, e.g. in cases where two functions call each other (function *A* calls function *B* in its code but function *B* also calls function *A*). For this there exist so called **[forward declaractions](forward_decl.md)** -- a forward declaration is informing that a function of certain name (and with certain parameters etc.) will be defined later in the code. Forward declaration look the same as a function definition, but it doesn't have a body (the part between `{` and `}`), instead it is terminated with a semicolon (`;`). Here is an example: + +``` +#include + +void printDecorated2(int x, int fancy); // forward declaration + +void printDecorated1(int x, int fancy) +{ + putchar('~'); + + if (fancy) + printDecorated2(x,0); // would be error without f. decl. + else + printf("%d",x); + + putchar('~'); +} + +void printDecorated2(int x, int fancy) +{ + putchar('>'); + + if (fancy) + printDecorated1(x,0); + else + printf("%d",x); + + putchar('<'); +} + +int main() +{ + printDecorated1(10,1); + putchar('\n'); // newline + printDecorated2(20,1); +} +``` + +which prints + +``` +~>10<~ +>~20~< +``` + +The functions `printDecorated1` and `printDecorated2` call each other, so this is the case when we have to use a forward declaration of `printDecorated2`. Also note the condition `if (fancy)` which is the same thing as `if (fancy != 0)` (imagine `fancy` being 1 and 0 and about what the condition evaluates to in each case). + +## Header Files, Libraries, Compilation/Building + +So far we've only been writing programs into a single source code file (such as `program.c`). More complicated programs consist of multiple files and libraries -- we'll take a look at this now. + +In C we normally deal with two types of source code files: + +- *.c files*: These files contain so called **[implementation](implementation.md)** of algorithms, i.e. code that translates into actual program instructions. These files are what's handed to the compiler. +- *.h files*, or **[header files](header_file.md)**: These files typically contain **declarations** such as constants and function headers (but not their bodies, i.e. implementations). + +When we have multiple source code files, we typically have pairs of *.c* and *.h* files. E.g. if there is a library called *mathfunctions*, it will consist of files *mathfunctions.c* and *mathfunctions.h*. The *.h* file will contain the function headers (in the same manner as with forward declarations) and constants such as [pi](pi.md). The *.c* file will then contain the implementations of all the functions declared in the *.h* file. But why do we do this? + +Firstly *.h* files may serve as a nice documentation of the library for programmers: you can simply open the *.h* file and see all the functions the library offers without having to skim over thousands of lines of code. Secondly this is for how multiple source code files are compiled into a single executable program. + +Suppose now we're compiling a single file named *program.c* as we've been doing until now. The compilation consists of several steps: + +1. The compiler reads the file *program.c* and makes sense of it. +2. It then creates an intermediate file called *program.o*. This is called an [object file](object_file.md) and is a binary compiled file which however cannot yet be run because it is not *linked* -- in this code all memory addresses are relative and it doesn't yet contain the code from external libraries (e.g. the code of `printf`). +3. The compiler then runs a **[linker](linker.md)** which takes the file *program.o* and the object files of libraries (such as the *stdio* library) and it puts them all together into the final executable file called *program*. This is called **linking**; the code from the libraries is copied to complete the code of our program and the memory addresses are settled to some specific values. + +So realize that when the compiler is compiling our program (*program.c*), which contains function such as `printf` from a separate library, it doesn't have the code of these functions available -- this code is not in our file. Recall that if we want to call a function, it must have been defined before and so in order for us to be able to call `printf`, the compiler must know about it. This is why we include the *stdio* library at the top of our source code with `#include ` -- this basically copy-pastes the content of the header file of the *stdio* library to the top of our source code file. In this header there are forward declarations of functions such as `printf`, so the compiler now knows about them (it knows their name, what they return and what parameters they take) and we can call them. + +Let's see a small example. We'll have the following files (all in the same directory). + +*library.h* (the header file): + +``` +// Returns the square of n. +int square(int n); +``` + +*library.c* (the implementation file): + +``` +int square(int x) +{ + // function implementation + return x * x; +} +``` + +*program.c* (main program): + +``` +#include +#include "library.h" + +int main(void) +{ + int n = square(5); + + printf("%d\n",n); + + return 0; +} +``` + +Now we will manually compile the library and the final program. First let's compile the library, in command line run: + +``` +gcc -c -o library.o library.c +``` + +The `-c` flag tells the compiler to only compile the file, i.e. only generate the object (*.o*) file without trying to link it. After this command a file *library.o* should appear. Next we compile the main program in the same way: + +``` +gcc -c -o program.o program.c +``` + +This will generate the file *program.o*. Note that during this process the compiler is working only with the *program.c* file, it doesn't know the code of the function `square`, but it knows this function exists, what it returns and what parameter it has thanks to us including the library header *library.h* with `#include "library.h"` (quotes are used instead of `<` and `>` to tell the compiler to look for the files in the current directory). + +Now we have the file *program.o* in which the compiled `main` function resides and file *library.o* in which the compiled function `square` resides. We need to link them together. This is done like this: + +``` +gcc -o program program.o library.o +``` + +For linking we don't need to use any special flag, the compiler knows that if we give it several *.o* files, it is supposed to link them. The file *program* should appear that we can already run and it should print + +``` +25 +``` + +This is the principle of compiling multiple C files (and it also allows for combining C with other languages). This process is normally automated, but you should know how it works. The systems that automate this action are called **[build systems](build_system.md)**, they are for example [Make](make.md) and [Cmake](cmake.md). When using e.g. the Make system, the whole codebase can be built with a single command `make` in the command line. + +Some programmers simplify this whole process further so that they don't even need a build system, e.g. with so called [header-only libraries](header_only.md), but this is outside the scope of this tutorial. + +As a bonus, let's see a few useful compiler flags: + +- `-O1`, `-O2`, `-O3`: Optimize for speed (higher number means better optimization). Adding `-O3` normally instantly speeds up your program. This is recommended. +- `-Os`: Optimize for size, the same as above but the compiler will try to make as small executable as possible. +- `-Wall -Wextra -pedantic`: The compiler will write more warnings and will be more strict. This can help spot many bugs. +- `-c`: Compile only (generate object files, do not link). +- `-g`: Include debug symbols, this will be important for [debugging](debugging.md). + + +## Advanced Data Types and Variables (Structs, Arrays) + +## Macros/Preprocessor ## Pointers -## More on Functions +## More on Functions (Recursion, Function Pointers) -## Dynamic Allocation +## Dynamic Allocation (Malloc) -## Debugging +## Debugging, Optimization ## Advanced Stuff diff --git a/exercises.md b/exercises.md index d80e0b9..d960b3e 100644 --- a/exercises.md +++ b/exercises.md @@ -3,17 +3,16 @@ Here let be listed exercises for the readers of this wiki. You can allow yourself to as many helpers and resources as you find challenging: with each problem you should either find out you know the solution or learn something new while solving it. 1. What's the difference between [free software](free_software.md) and [open source](open_source.md)? -2. Say we have an algorithm that finds all pairs of equal numbers in an array of numbers of length *N* and adds all of these (unordered) pairs to a set *S*. The algorithm is: `for i := 0 to N: for j := 0 to N: if numbers[i] == numbers[j]: add(S,pair(i,j))`. How can we optimize the algorithm in terms of its execution speed (i.e. make it perform fewer operations)? How did the asymptotic time complexity ("big O") class change? +2. Say we have an algorithm that finds all pairs of equal numbers in an array of numbers of length *N* and adds all of these (unordered) pairs to a set *S*. The algorithm is (pseudocode): `for i := 0 to N: for j := 0 to N: if numbers[i] == numbers[j]: add(S,pair(i,j))`. How can we optimize the algorithm in terms of its execution speed (i.e. make it perform fewer operations while keeping its results the same)? How did the asymptotic time complexity ("big O") class change? 3. In computer graphics, what is the difference between ray casting, ray tracing and path tracing? - ## Solutions A solution to each problem should be listed here -- keep in mind there may exist other solutions that those listed here. **solution 1**: -Both movements share very similar rules of licensing and technically free software and open-source are largely the same. However, free software is fundamentally aiming for the creation ethical software -- that which respects its user's freedom -- while open source is a later movement that tries to adapt free software for the business and abandons the pursuit of ethics. +Both movements share very similar rules of licensing and technically free software and open-source are largely the same. However, free software is fundamentally aiming for the creation of ethical software -- that which respects its user's freedom -- while open source is a later movement that tries to adapt free software for the business and abandons the pursuit of ethics, i.e. it becomes corrupted by capitalism and no longer minds e.g. proprietary dependencies. **solution 2**: @@ -21,7 +20,7 @@ In the given algorithm we compare all numbers twice. This can be avoided by not ``` for i := 0 to N: - add(S,i,i) // no need to compare + add(S,i,i) // no need to compare for i := 0 to N: for j := i + 1 to N: @@ -29,7 +28,7 @@ for i := 0 to N: add(S,pair(i,j)) ``` -While the first algorithm performs N^2 comparisons, the new one only needs N - 1 + N - 2 + N - 3 + ... ~= N * N / 2 = N^2 / 2 comparisons. Even though the new version is always twice as fast, its time complexity class remains the same, that is O(N^2). +While the first algorithm performs N^2 comparisons, the new one only needs N - 1 + N - 2 + N - 3 + ... ~= N * N / 2 = N^2 / 2 comparisons. Even though the new version is always twice as fast, its time complexity class remains the same, that is O(N^(2)). **solution 3**: diff --git a/fixed_point.md b/fixed_point.md index 865ea20..b3ef033 100644 --- a/fixed_point.md +++ b/fixed_point.md @@ -1,10 +1,10 @@ # Fixed Point -Fixed point arithmetic is a simple and often [good enough](good_enough.md) way of dealing with fractional (non-integer) numbers, as opposed to [floating point](floating_point) which is from our point of view considered a bad solution for most programs. +Fixed point arithmetic is a simple and often [good enough](good_enough.md) way of dealing with fractional (non-integer) numbers, as opposed to [floating point](float.md) which is from our point of view considered a bad solution for most programs. -In 99% cases when you think you need floating point, fixed point is actually what you need. +Probably in 99% cases when you think you need floating point, fixed point is actually what you need. -Fixed point has these advantages over floating point: +Fixed point has at least these advantages over floating point: - It is **easier to understand and better predictable**, less tricky, [KISS](kiss.md), [suckless](sukless.md). (Float's IEEE 754 standard is 58 pages long, the paper *What Every Computer Scientist Should Know About Floating-Point Arithmetic* has 48 pages.) - **Doesn't require a special hardware coprocessor** and so doesn't introduce a [dependency](dependency.md). Programs using floating point will run extremely slowly on systems without float hardware support as they have to emulate the complex hardware in software, while fixed point will run just as fast as integer arithmetic. @@ -13,16 +13,16 @@ Fixed point has these advantages over floating point: ## How It Works -Fixed point uses some fixed (hence the name) number of digits (bits in binary) for the fractional part (whereas floating point's fractional part varies). +Fixed point uses some fixed (hence the name) number of digits (bits in binary) for the fractional part (whereas floating point's fractional part varies in length). -So for example, when working with 16 bit numbers, we may choose to use 12 bits for the integer part and the remaining 4 for the fractional part. This puts an imaginary radix point after the first (highest) 12 bits of the number in binary representation, like this: +So for example when working with 16 bit numbers, we may choose to use 12 bits for the integer part and the remaining 4 for the fractional part. This puts an imaginary radix point after the first (highest) 12 bits of the number in binary representation, like this: ``` abcdefghijkl mnop ------------.---- ``` -The whole number `abcdefghijkl` can take on values from 0 to 4095 (or -2048 to 2047 when using [two's complement](twos_complement.md) -- yes, fixed point works as signed type too). The fraction can take 16 (2^4) values, meaning we subdivide every whole number into 16 parts (we say our *scaling factor* is 1/16). +The whole number `abcdefghijkl` can take on values from 0 to 4095 (or -2048 to 2047 when using [two's complement](twos_complement.md) -- yes, fixed point works as signed type too). The fraction can take 16 (2^(4)) values, meaning we subdivide every whole number into 16 parts (we say our *scaling factor* is 1/16). You can also imagine it like this: when you e.g. write a 3D game and measure your dimensions in meters, fixed point just means considering a denser grid; so you just say your variables will count centimeters rather than meters and everything will just work. (Practically however you wouldn't use centimeters but power of 2 subdivisions, e.g. 256ths of a meter.) diff --git a/how_to.md b/how_to.md index d16db59..b78ee6e 100644 --- a/how_to.md +++ b/how_to.md @@ -2,6 +2,8 @@ WELCOME TRAVELER +{ Don't hesitate to contact me. ~drummyfish } + Are you tired of [bloat](bloat.md) and can't stand [shitty](shit.md) software like [Windows](windows.md) anymore? Do you hate [capitalism](capitalism.md)? Do you also hate the [fascist alternatives](tranny_software.md) you're being offered? Do you just want to create a genuinely good technology without [bullshit](bullshit.md) that would help all people? Do you just want to share knowledge freely without [censorship](censorship.md)? You have come to the right place. Firstly let us welcome you, no matter who you are, no matter your political opinions, your past and your skills, we are glad to have you here. Remember, you don't have to be a programmer to help and enjoy LRS. LRS is a lifestyle, a philosophy. Whether you are a programmer, artist, educator or just someone passing by, you are welcome, you may enjoy our culture and its fruit and if you want, you can help enrich it. @@ -20,4 +22,4 @@ If you don't know how to start, here are some basic steps: 5. Finally start creating something: either programs or other stuff like [free art](free_culture.md), educational materials, contributions to this Wiki etc. 6. profit??? -Would you like to create [LRS](lrs.md) but don't have enough spare time/money to make this possible? Read about [making living](living.md) with LRS. \ No newline at end of file +Would you like to create [LRS](lrs.md) but don't have enough spare time/money to make this possible? Read about [making living](living.md) with LRS. diff --git a/main.md b/main.md index 6e9d6b1..71debb9 100644 --- a/main.md +++ b/main.md @@ -2,9 +2,9 @@ This is a Wiki for [less retarded software](lrs.md) (LRS) and related topics. -This wiki is **NOT** a satire nor a joke. +This wiki is **NOT** a satire. -**Before contributing please read the [rules & style](wiki_style.md)!** +**Before contributing please read the [rules & style](wiki_style.md)!** {But contributions aren't really accepted RN :) ~drummyfish } Pay us a visit on the [Island](island.md)! And come mourn with us in the [cathedral](cathedral.md), because **technology is dying**. @@ -12,7 +12,7 @@ If you're new here, you may want to read answers to [frequently asked questions] ## What Is Less Retarded Software -Well, we're trying to figure this out on this wiki, but it is greatly related to [suckless](suckless.md), [Unix](unix.md), [KISS](kiss.md), [free](free_software.md) and sustainable software. LRS stands opposed to all [shittiness](shit.md) of so called ["modern"](modern.md) software. For more details see the article about [LRS](lrs.md). +Well, we're trying to figure this out on this wiki, but it is greatly related to [suckless](suckless.md), [Unix](unix.md), [KISS](kiss.md), [free](free_software.md), selfless and sustainable software created to maximally help all living beings. LRS stands opposed to all [shittiness](shit.md) of so called ["modern"](modern.md) software. For more details see the article about [LRS](lrs.md). ## Are You a Noob? diff --git a/minimalism.md b/minimalism.md index bac982d..dbcf1a3 100644 --- a/minimalism.md +++ b/minimalism.md @@ -1,7 +1,7 @@ # Technological Minimalism -Technological minimalism is a philosophy of designing technology to be as simple as possible while still achieving given goal. Minimalism is one of the most (if not the most) important concepts in [programming](programming.md). +Technological minimalism is a philosophy of designing technology to be as simple as possible while still achieving given goal. Minimalism is one of the most (if not the most) important concepts in [programming](programming.md) technology in general. Minimalism goes against complexity of technology which always brings huge cost and dangers, e.g. the cost of maintenance and further development, obscurity, inefficiency ("[bloat](bloat.md)", wasting resources), the increased risk of bugs, errors and failure. -Up until recently in history every engineer would tell you that *the better machine is that with fewer moving parts*. This still seems to hold in mathematics, an area inhabited by the smartest people, where there is a tendency to look for the most minimal equations -- such equations are considered [beautiful](beauty.md). Science also knows this rule as the Occam's razor. In technology invaded by aggressive commercialization the situation is different, minimalism lives only in the underground as part of such philosophies as [suckless](suckless.md), [Unix](unix_philosophy.md), [KISS](kiss.md), countercomplex and, of course, [less retarded software](lrs.md). +Up until recently in history every engineer would tell you that *the better machine is that with fewer moving parts*. This still seems to hold in mathematics, an area inhabited by the smartest people, where there is a tendency to look for the most minimal equations -- such equations are considered [beautiful](beauty.md). Science also knows this rule as the Occam's razor. In technology invaded by aggressive commercialization the situation is different, minimalism lives only in the underground as part of such philosophies as [suckless](suckless.md), [Unix](unix_philosophy.md), [KISS](kiss.md), countercomplex and, of course, [less retarded software](lrs.md). This is bad. -Under [capitalism](capitalism.md) technological minimalism dies with possibly only the "shallow" kind of minimalism surviving. This so called "minimalism" tries to make things look minimal only aesthetically and hides ugly overcomplicated internals under this facade. [Apple](apple.md) is known for this [shit](shit.md). \ No newline at end of file +Under [capitalism](capitalism.md) technological minimalism dies with possibly only the "shallow" kind of minimalism ([pseudominimalism](pseudominimalism.md)) surviving. This so called "minimalism" tries to make things look minimal only aesthetically and hides ugly overcomplicated internals under this facade. [Apple](apple.md) is known for this [shit](shit.md). \ No newline at end of file