forked from xolatile/xhartae
Wrote more text... /:
This commit is contained in:
parent
f7dce87ece
commit
e7dc385b56
@ -69,8 +69,24 @@ Memory management is a whole new topic that's too complex to cover it now in det
|
||||
that every program can read, write or execute only parts of the memory that the kernel allows it. Program can request new memory or release old memory, so some other programs can
|
||||
use it. We'll learn to use program called Valgrind to find and fix memory related bugs in later chapters. We rely on functions 'calloc', 'realloc' and 'free' from <stdlib.h>
|
||||
header file, and we'll avoid 'malloc', and use 'realloc' carefully, because they leave new memory uninitialized.
|
||||
|
||||
We're internally using function 'calloc' to request new memory, function 'realloc' to enlarge existing memory and function 'free' to release old memory, data that won't be used
|
||||
later in the program. It's important to "free" all "malloc/calloc/realloc"-ed memory when program finishes successfully, and in some special cases, even when program fails and
|
||||
aborts. It's important for safety to do so, think of it like open and close braces, if you have some allocations, you should deallocate them later.
|
||||
|
||||
Some examples of using them directly (not wrapping them like I like to do) are:
|
||||
*/
|
||||
|
||||
/**
|
||||
char * data = NULL;
|
||||
|
||||
data = malloc (20 * sizeof (* data)); // Allocates 20 bytes of memory for 'data'.
|
||||
data = calloc (20, sizeof (* data)); // Allocates 20 bytes also, but initializes them to 0 value.
|
||||
data = realloc (data, 20 * sizeof (* data)); // When 'data' is null pointer, it will be same as 'malloc', else it will reallocate more memory (for correct usage).
|
||||
|
||||
free (data); // Deallocates memory, we'll talk about "double free" later.
|
||||
**/
|
||||
|
||||
void * allocate (int size) {
|
||||
char * data = NULL;
|
||||
|
||||
|
@ -33,30 +33,39 @@ General code formatting should follow these rules in C programming language:
|
||||
- Avoid writing a lot of comments, or avoid them completely, except for license notice, this book is an exception!
|
||||
- Think very carefully if you'll limit the line length, it depends on your workflow and attention span... For me, 180 characters per line.
|
||||
- If you want, use pagination, but I don't recommend it when working with C. I use it in Ada, because comments there start with "--".
|
||||
- Always use snake case (this_naming_style), for enumerations and macros (THIS_STYLE), and never put underscore before or after the identifier.
|
||||
- Always use snake case (this_style), for enumerations and macros (THIS_STYLE), and never put underscore before or after the identifier.
|
||||
|
||||
Spacing:
|
||||
|
||||
- Before and after:
|
||||
|
||||
A: B: C: D: E: F:
|
||||
+ += & &= && ==
|
||||
- -= | |= || !=
|
||||
* *= ^ ^= ! <=
|
||||
/ /= << <<= ~ >=
|
||||
% %= >> >>= ? >
|
||||
= : <
|
||||
A: B: C: D: E: F:
|
||||
+ += & &= && ==
|
||||
- -= | |= || !=
|
||||
* *= ^ ^= ! <=
|
||||
/ /= << <<= ? >=
|
||||
% %= >> >>= : <
|
||||
= ~ >
|
||||
|
||||
A) Standard operators, addition, subtraction, multiplication, division, modulus and assignment.
|
||||
B) Extension of standard operators, that'll use left-hand variable as first operand.
|
||||
C) Binary operators, bit-and, bit-or, bit-xor, bit-shift-left, bit-shift-right and bit-not.
|
||||
D) Again, same extension but for binary operators, that'll use left-hand variable as first operand (except bit-not as it's unary).
|
||||
E) Logical operators, and, or, not and operators '?' and ':' are used together, as they form ternary operator.
|
||||
F) Comparison operators, equals, not-equals, less-or-equal, greater-or-equal, less and greater.
|
||||
|
||||
Some more symbols are also operators, but my advice is not to treat them as such, just consider them some kind of special cases.
|
||||
|
||||
- Before:
|
||||
|
||||
( { [
|
||||
( { [
|
||||
- After:
|
||||
|
||||
) } ] , ;
|
||||
) } ] , ;
|
||||
|
||||
- None (unary + and -):
|
||||
|
||||
. -> " ' ++ -- + -
|
||||
. -> " ' ++ -- + -
|
||||
|
||||
Exceptions:
|
||||
|
||||
@ -162,17 +171,17 @@ eye on how are they aligned and named. I'll reimplement some standard functions,
|
||||
#define SIGNAL_ARROW_RIGHT (0X435B1B)
|
||||
#define SIGNAL_ARROW_LEFT (0X445B1B)
|
||||
|
||||
enum { /* I like to align enumerations with 10, 20 or 40 characters per name, and optionally use NAME_ as prefix and NAME_COUNT as last element. */
|
||||
enum { // I like to align enumerations with 10, 20 or 40 characters per name, and optionally use NAME_ as prefix and NAME_COUNT as last element.
|
||||
EFFECT_NORMAL, EFFECT_BOLD, EFFECT_ITALIC, EFFECT_UNDERLINE, EFFECT_BLINK, EFFECT_REVERSE,
|
||||
EFFECT_COUNT
|
||||
};
|
||||
|
||||
enum { /* Because of text auto-completition, it's always easy to find what I want, or to use NAME_COUNT in arrays. */
|
||||
enum { // Because of text auto-completition, it's always easy to find what I want, or to use NAME_COUNT in arrays.
|
||||
COLOUR_GREY, COLOUR_RED, COLOUR_GREEN, COLOUR_YELLOW, COLOUR_BLUE, COLOUR_PINK, COLOUR_CYAN, COLOUR_WHITE,
|
||||
COLOUR_COUNT
|
||||
};
|
||||
|
||||
enum { /* This is also one of my preferences, to use CHARACTER_NULL or CHARACTER_LINE_FEED instead of '\0' or '\n' in special (non-string) cases. */
|
||||
enum { // This is also one of my preferences, to use CHARACTER_NULL or CHARACTER_LINE_FEED instead of '\0' or '\n' in special (non-string) cases.
|
||||
CHARACTER_NULL, CHARACTER_START_HEADER, CHARACTER_START_TEXT, CHARACTER_END_TEXT,
|
||||
CHARACTER_END_TRANSMISSION, CHARACTER_ENQUIRY, CHARACTER_ACKNOWLEDGE, CHARACTER_BELL,
|
||||
CHARACTER_BACKSPACE, CHARACTER_TAB_HORIZONTAL, CHARACTER_LINE_FEED, CHARACTER_TAB_VERTICAL,
|
||||
@ -184,16 +193,16 @@ enum { /* This is also one of my preferences, to use CHARACTER_NULL or CHARACTER
|
||||
CHARACTER_COUNT
|
||||
};
|
||||
|
||||
extern void in (void * data, int size); /* We'll use these functions later as core standard input/output functions. */
|
||||
extern void in (void * data, int size); // We'll use these functions later as core standard input/output functions.
|
||||
extern void out (void * data, int size);
|
||||
|
||||
extern void echo (char * data); /* Function 'echo' behaves similar to 'out', but it's easier to use because it doesn't require size. */
|
||||
extern void echo (char * data); // Function 'echo' behaves similar to 'out', but it's easier to use because it doesn't require size.
|
||||
|
||||
extern void fatal_failure (int condition, char * message); /* Some functions fail, and sometimes we want to abort everything, crash and leak memory, we just don't care. */
|
||||
extern void fatal_failure (int condition, char * message); // Some functions fail, and sometimes we want to abort everything, crash and leak memory, we just don't care.
|
||||
|
||||
extern void limit (int * value, int minimum, int maximum);
|
||||
|
||||
extern void * allocate ( int size); /* Core memory management functions with some minimal error checking. */
|
||||
extern void * allocate ( int size); // Core memory management functions with some minimal error checking.
|
||||
extern void * reallocate (void * data, int size);
|
||||
extern void * deallocate (void * data );
|
||||
|
||||
|
@ -9,4 +9,62 @@ It is distributed in the hope that it will be useful or harmful, it really depen
|
||||
#ifndef CHAPTER_1_HEADER
|
||||
#define CHAPTER_1_HEADER
|
||||
|
||||
/*
|
||||
Now that you've read the chapter zero, we should get into some technical details about C programming language. This will be the most imporant chapter for people who know some
|
||||
other lower level programming language, or who intuitively understand "building blocks" of some system. Below is just a simple matrix of them, 8 x 4, so you can see that there are
|
||||
really 32 keywords (ANSI C standard, I dislike newer standards), and even more below we'll categorize them.
|
||||
|
||||
- Keywords:
|
||||
|
||||
static signed if typedef
|
||||
extern unsigned else enum
|
||||
const float for union
|
||||
auto double do struct
|
||||
register char while return
|
||||
volatile int switch goto
|
||||
sizeof short case break
|
||||
void long default continue
|
||||
|
||||
Keywords that you should never use, under any circumstances (except for writing your own C compiler or working in embedded) are:
|
||||
|
||||
- register: Hint to the compiler that some variable will be used a lot, so it can be stored in CPU register, modern compilers ignore this keyword.
|
||||
- volatile: Hint to the compiler that some variable may be changed by some external source. Such a cool keyword, but never use it.
|
||||
- auto: It specifies automatic storage duration for local variables inside a block. Simply, variable won't exist outside {} block it's defined in.
|
||||
- signed: We'll talk about types in C more, but this is always assumed, so use only 'unsigned', when you really need to.
|
||||
- union: You'll have very little excuse to use unions, because they often don't go well with type checking and introduce complexity for no reason.
|
||||
- goto: I'm kidding, feel free to use 'goto' statement, it's not harmful, some people just abused it to the point of it being bullied.
|
||||
|
||||
Keywords that you should really consider not to use in general, but only for some very specific cases:
|
||||
|
||||
- const: Constant qualifier sometimes tells to the compiler that a value won't be changed. Use it only to silence the compiler warnings...
|
||||
- unsigned: Again, you shouldn't care if your variable is signed or unsigned, because C really likes integers, and hates naturals. We'll talk more about it.
|
||||
- float: Unless you're making a game engine with GPU acceleration or neural network, I wouldn't use this type at all due to it's limitations.
|
||||
- double: Well, same as 'float', but twice bigger and more precise floating point values. You'll see it being used very rarely.
|
||||
- short: Use it only to silence warnings, especially those from XCB and Xlib libraries, for whatever reason (read: X11) they use million different types.
|
||||
- long: Also use this only to silence warnings, because some standard library functions use this type, pure C-hating cancer...
|
||||
- typedef: I don't like it at all, but this one is my personal preference, because it just introduces unneeded mental overhead when programming.
|
||||
- do: It can only be used before '{', then you do the loop thing, then '}' and then 'while' statement. I prefer just to use 'for' everywhere.
|
||||
|
||||
Okay, now we're left with following actually useful and C-loving keywords, 18 of them, that I'll cover more:
|
||||
|
||||
- char: Type for storing ASCII characters, 8 bits wide, implicitly casted to 'int' in sometimes, arrays that use them are string literals.
|
||||
- int: Type for storing signed numerical values, 32 bits wide, most number literals are casted to this type, compiler will warn you for mixing types.
|
||||
- void: This is a black hole, nothing can escape it.
|
||||
- sizeof: Some people say this behaves like a function, but they are wrong, it's a statement. It literally does what is says, more on that later...
|
||||
- static: This qualifier has several meanings, that function or variable will only be used in that file or when inside a function, that variables persists.
|
||||
- extern: This qualifier is more simple, and implicit in older compilers, newer ones warn when it's not used. Something will be used outside that file.
|
||||
- if: If some condition(s) are met (equal to true or non-zero value), do the thing specified in the block.
|
||||
- else: With 'else' you can "bind" multiple 'if' statements, but know that you can completely avoid it, and get the same results.
|
||||
- for: Very complex kind of loop statement, that leads to segmentation faults and many other memory and safety related bugs. I love to use it.
|
||||
- while: Very simple king of loop statement, that leads to segmentation faults and many other memory and safety related bugs. I don't love to use it.
|
||||
- switch: This statement is the most powerful in the whole C language, it's not just if-else made pretty, we'll see examples later.
|
||||
- case: Used only inside 'switch' statement, it sets some number literal as an implicit label, so when the expression in 'switch' is equals it, it jumps there.
|
||||
- default: Used only because C didn't force curly brackets everywhere back when it was made, but every 'switch' should have just one 'default'.
|
||||
- enum: Sometimes treated as type (with 'typedef'), and always very good way to define a lot of constants, we'll talk about them more.
|
||||
- struct: I really advice against using structures, but most libraries use them, so you need to know how they work. In C, they are very weak part of the language.
|
||||
- return: Used in functions to return from them with or without a result (return value). It's best when function only uses it once.
|
||||
- break: When inside a loop, this statement will exit the loop. In newer standards it can take simple arguments, but we'll see why that's bad.
|
||||
- continue: Even more specific case, when inside a loop, this statement will skip to the end of the loop, and then continue again.
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user