forked from xolatile/xhartae
139 lines
12 KiB
C
139 lines
12 KiB
C
/*
|
|
Copyright (c) 2023 : Ognjen 'xolatile' Milan Robovic
|
|
|
|
Xhartae is free software! You will redistribute it or modify it under the terms of the GNU General Public License by Free Software Foundation.
|
|
And when you do redistribute it or modify it, it will use either version 3 of the License, or (at yours truly opinion) any later version.
|
|
It is distributed in the hope that it will be useful or harmful, it really depends... But no warranty what so ever, seriously. See GNU/GPLv3.
|
|
*/
|
|
|
|
#ifndef CHAPTER_1_HEADER
|
|
#define CHAPTER_1_HEADER
|
|
|
|
#include "chapter_0.h" // We need this header file for some core enumeration definitions and function declarations.
|
|
|
|
/*
|
|
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. Also, keep in mind that I'll briefly talk about other C standards such
|
|
as K&R, C99, etc., and use parts of them in some places, so you don't get confused when you see them in other peoples' source code.
|
|
|
|
- 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 (compiler warnings or using some libraries):
|
|
|
|
- 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.
|
|
|
|
Now, of those 18 actually useful C keywords, I like to avoid 'struct', 'switch', 'case', 'default', 'while', and use (functional) 'static' and 'extern' only in order to silence
|
|
compiler warnings, 'static' inside a function is more useful. That leaves us (me) with 12 C keywords that I love, out of complete 32 keywords in ANSI C standard. However, we'll
|
|
see that sometimes is preferable to use switch statement somewhere, or while loop when for loop feels like overkill. In most real-world cases, you'll need to use some API or
|
|
library that internally used structures everywhere, so you'll need to adapt to it, we'll see examples later...
|
|
|
|
So, real men need these keywords { char, int, void, sizeof, static, if, else, for, enum, return }, and use the rest of them in order to silence compiler warnings, use some
|
|
standard library functions, clean the source code or access an API / library / header file. Lets see some more examples and keep in mind code formatting...
|
|
|
|
@C
|
|
extern int this_is_kind (kind_type this);
|
|
// extern - we declare this function as external one, because we'll create an object file (.o), and link it with other programs (or object files).
|
|
// int - we set 'int', integer as return type of this function, and use 0 as false, and 1 as true, instead of 'bool' type from <stdbool.h>.
|
|
// this_is_kind - we named our function like this, you'll see more of verbose naming when I write programs, because I think it's better...
|
|
// kind_type - we choose the type of arguments in our function, since our function deals with 'kind', we choose proper 'kind_type'.
|
|
// this - we named our argument about what's it supposed to be, use similar approach in return type, function, argument type and argument names.
|
|
@
|
|
|
|
Before continuing, lets describe some imporant types in C very simply:
|
|
|
|
Word: Bytes: Bits: Kind: Minimum: Maximum:
|
|
void / / Black hole / /
|
|
void * 8 64 Memory address / /
|
|
char 1 8 Integer -128 127
|
|
short 2 16 Integer -32768 32767
|
|
int 4 32 Integer -2147483648 2147483647
|
|
long 8 64 Integer -9223372036854775808 9223372036854775807
|
|
unsigned char 1 8 Natural 0 256
|
|
unsigned short 2 16 Natural 0 65535
|
|
unsigned int 4 32 Natural 0 4294967295
|
|
unsigned long 8 64 Natural 0 18446744073709551615
|
|
float 4 32 Real (IEEE754) / /
|
|
double 8 64 Real (IEEE754) / /
|
|
|
|
Note that you shouldn't care for now about 'void' and 'void *', because they're special cases, nor about their minimum and maximum.
|
|
*/
|
|
|
|
enum {
|
|
FILE_TYPE_TEXT, FILE_TYPE_COMMON_ASSEMBLY, FILE_TYPE_FLAT_ASSEMBLY, FILE_TYPE_GNU_ASSEMBLY,
|
|
FILE_TYPE_NETWIDE_ASSEMBLY, FILE_TYPE_YET_ANOTHER_ASSEMBLY, FILE_TYPE_C_SOURCE, FILE_TYPE_C_HEADER,
|
|
FILE_TYPE_ADA_BODY, FILE_TYPE_ADA_SPECIFICATION, FILE_TYPE_CPP_SOURCE, FILE_TYPE_CPP_HEADER,
|
|
FILE_TYPE_COUNT
|
|
};
|
|
|
|
extern int character_is_uppercase (char character); // Notice how we align those functions, I believe this improves the readability of any program, in any programming language.
|
|
extern int character_is_lowercase (char character); // Some people would just use 'ischrupp' or something, but I hate reading code written like that...
|
|
extern int character_is_digit (char character); // Important note is also that a programming language is not, and it should be like natural language, why?
|
|
extern int character_is_blank (char character); // Because we need strict rules in programming language, same like in mathematical languages, now now, don't be scared.
|
|
extern int character_is_alpha (char character);
|
|
extern int character_is_symbol (char character);
|
|
extern int character_is_visible (char character);
|
|
extern int character_is_invisible (char character);
|
|
extern int character_is_escape (char character);
|
|
extern int character_is_underscore (char character);
|
|
extern int character_is_hexadecimal (char character);
|
|
|
|
extern int character_compare_array (char character, char * character_array); // This function is singled out, because it's different from those above, and we use it internally.
|
|
|
|
extern int file_open (char * name, int mode);
|
|
extern int file_close (int file);
|
|
extern void file_read (int file, void * data, int size);
|
|
extern void file_write (int file, void * data, int size);
|
|
extern int file_seek (int file, int whence);
|
|
extern int file_size (char * name);
|
|
extern int file_type (char * name);
|
|
extern void * file_record (char * name);
|
|
|
|
#endif
|