2023-11-13 21:03:29 -05:00
# ifndef CHAPTER_0_HEADER
# define CHAPTER_0_HEADER
/*
2023-12-03 07:19:51 -05:00
In this chapter , you ' ll learn about :
- Code formatting
- Operators
- Function and variable declarations
- Enumerations
- Some basic functions
- String and memory functions
2023-11-13 21:03:29 -05:00
It ' s very important that your code is aligned , readable and safe . So , we ' ll talk about it even before the first chapter , the so - called " zero chapter " . I write assembly and Ada
beside C , but still , 90 % of my projects are written in C programming language ! Why ? Because C is like a girl that ' s a bit older than you , quiet but very smart and respectable , and
you don ' t want to piss her off . Ada is more like nerdy girl who doesn ' t know what she wants , while assembly is ghost girl in your closet that you pretend not to see at night . So ,
this Ada girl was my first serious love , and she had a book " Ada Coding Standard " , which is like a bible to her . It ' s a bit fanatical , but it has some good points which I ' ll
discuss below without copy / paste , and apply to C .
Lets see some good examples of C code ( in my opinion obviously ) , I ' ll provide few of them , and note that I use the first style in them . Needless to say , as this book is aimed to
people who don ' t know C programming language , or are in phase of learning it , you should ( and eventually will ) develop your own style of writing it , but you shouldn ' t force it at
the start , it should happen over time , naturally . Just be sure to always be consistent , and to avoid anything that ' ll generate compiler warnings .
General code formatting should follow these rules in C programming language :
2023-11-26 06:34:52 -05:00
- Always use tabs for indentation , and spaces for alignment . You ' ll hear people say the otherwise , don ' t trust them , they don ' t know .
2023-11-13 21:03:29 -05:00
- Separate most ( not all ! ) operators with space before and after it . We ' ll provide exceptional cases for this rule below .
- Align most ( not all ! ) operators horizontally , and logical units vertically . Again , examples are the best showcase .
- Always use curly braces and round braces , even when they ' re not required by the compiler . Most linters warn about this .
- Avoid writing a lot of comments , or avoid them completely , except for license notice , this book is an exception ! Also , don ' t write GPL notice like I do . . .
- 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_style ) , for enumerations and macros ( THIS_STYLE ) , and never put underscore before or after the identifier .
2023-11-26 06:34:52 -05:00
+ Feel free the break the rules if , by your jugdement , that will improve readability or emphasize the intention , I break them too .
2023-11-13 21:03:29 -05:00
For now , don ' t worry about what ' s an identifier , compiler , linter , those scary and unknown words will be explained later , when the time comes .
Spacing :
- Before and after :
A : B : C : D : E : F :
+ + = & & = & & = =
- - = | | = | | ! =
* * = ^ ^ = ! < =
/ / = < < < < = ? > =
% % = > > > > = : <
= ~ >
A ) Standard operators , addition , subtraction , multiplication , division , modulus and assignment ( except assignment obviously ) .
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 .
2023-11-26 06:34:52 -05:00
Some more symbols are also operators ( and some are not ) , but my advice is not to treat them as such , just consider them some kind of special cases .
2023-11-13 21:03:29 -05:00
- Before :
( { [
- After :
) } ] , ;
- None ( unary + and - ) :
. - > " ' ++ -- + -
Exceptions :
- When using more complicated expressions , apply rules above , or make an exception in them if you think you ' ll make it more readable by breaking the rules .
- When merging consecutive opened or closed braces , for example , like when you ' re nesting function calls .
- When declaring functions , align return types and open braces , and by taste , argument types for logical units .
- When declaring variables , align types and asignment operators , and by taste , pointer or array operators .
Naming :
- Have you ever wondered , what the hell is stdio , unistd , stdint , termios , errno , strcat , strchr , strndupa , memcpy , atoi , fgetc , puts , lseek . . . ? I did wonder .
- Are identifiers such as string_concatenate , memory_copy , error_id , integer , boolean , constant , string_to_integer , file_offset too long to type . . . ? I think not .
All that aside , C is an old programming language , and people who have made it knew a lot more about how computers work at their time than most people know nowdays . Hardware got
faster and cheaper , but also more complex . We have enough memory today to edit our text files with word - wrapping enabled , highlight the syntax , and to store large files due to
very long identifiers , 8 - space - wide indentation instead of a single tab and overly complicated OOP code . If you can handle those names above , feel free to use them , but be
consistent . I can ' t handle them , so I tolerate them with C keywords , because I ' d actually prefer " constant / integer / character " over " const / int / char " . . . You ' ll notice that
C has mixed them in keywords , and most standard library headers mix them too . . .
- Keywords : register double short signed break while / int char extern auto enum struct
- Headers : string memory limits time complex threads / stdio ctype stdint unistd fcntl termios
- Functions : read write open close exit clock / strncmp memcpy atoi fputc tcsetattr usleep
About that , I don ' t even know where to begin about talking how bad it is for readability . . . But lets ignore that for now and focus on code formatting . Text you see above this
paragraph is enough to get you started , and text below is just expanding a little more on common sense when you ' re formatting your code . For example , how to align consequtive
external or internal function or variable declarations , how to align if statement condition ( s ) or switch statement body , and more .
There ' s not much to say here , we ' ll talk about function declarations more in later chapters , as they are optional , but I like to use them . However , you should avoid to use too
many function agruments , and always place them in consistent and logical order .
@ C
// Internal and external function declaration:
2023-11-26 06:34:52 -05:00
static int string_copy_limit ( char * destination , char * source , int limit ) ;
2023-11-13 21:03:29 -05:00
extern int32_t string_copy ( char * string_a ,
char * string_b ,
int32_t count ) ;
extern size_t copy_string_n (
string_t a ,
string_t b ,
size_t n
) ;
2023-11-26 06:34:52 -05:00
// And you can improve last 2 examples by using 'destination' for 'string_0/a' and 'source' for 'string_1/b', since it's more clear what the function does.
2023-11-13 21:03:29 -05:00
@
Internal ( ' static ' ) and external ( ' extern ' ) variable declarations are different from function declarations , because you need to initialize internal variables to some value , I like
to provide either " zero " value for them , with the corresponding type ( 0 , 0.0 , ' \0 ' , NULL . . . ) , or an invalid value ( - 1 , EOF . . . ) . Some C compilers and linters will warn you about
redeclaring them , some will warn you that they ' re already initialized to zero , so when you some across those warnings , you ' ll know how to fix them . I hate this part of C . . .
@ C
// Internal and external variable declaration:
2023-11-26 06:34:52 -05:00
static int curses_active = 0 ; // You can declare and define internal variables right away, all in one line.
2023-11-13 21:03:29 -05:00
static char curses_signal = ' \0 ' ;
static char * curses_screen = NULL ;
2023-11-26 06:34:52 -05:00
extern unsigned int positive ; // You need to declare external variables without initializing them immediately.
2023-11-13 21:03:29 -05:00
extern int negative ;
extern int * * coordinate_system ;
2023-11-26 06:34:52 -05:00
unsigned int positive = + 1 ; // And then to define them separately, unlike internal variables.
int negative = - 1 ;
int * * coordinate_system = NULL ;
static void ( * encode_type_0 [ TYPE_0_COUNT ] ) ( void ) = { NULL } ; // We're declaring arrays of function pointers this way, we'll cover them in later chapters.
2023-11-13 21:03:29 -05:00
static char * ( * encode_type_1 [ TYPE_1_COUNT ] ) ( int l ) = { NULL } ;
static int ( * encode_type_2 [ TYPE_2_COUNT ] ) ( int l , int r ) = { NULL } ;
extern xcb_window_t blesses_window ;
extern xcb_gcontext_t blesses_context ;
extern xcb_pixmap_t blesses_pixmap ;
extern xcb_connection_t * blesses_connection ;
extern xcb_screen_t * blesses_screen ;
extern xcb_image_t * blesses_image ;
2023-11-26 06:34:52 -05:00
xcb_window_t blesses_window ; // Here, same example for external variables, but you don't even need to initialize them.
xcb_gcontext_t blesses_context ; // If you know what you're doing, and when they'll be initialized, you can leave them like this.
xcb_pixmap_t blesses_pixmap ;
xcb_connection_t * blesses_connection ;
xcb_screen_t * blesses_screen ;
xcb_image_t * blesses_image ;
2023-11-13 21:03:29 -05:00
@
Only for ' main ' function , you shouldn ' t add ' static ' or ' extern ' keywords before it . Every C file needs to have exactly one ' main ' function , it ' s the programs ' entry point . Also ,
some people like to define their own types , with keyword ' typedef ' , I ' m not a fan of it , since in C types are also keywords unlike in Ada . Again , it ' ll become more clean in future
2023-11-26 06:34:52 -05:00
chapters why I dislike user - defined types , unions and structures . That doesn ' t mean we won ' t use them tho , because I need to show - case their usage . Also , as for main function , it
can have either ' void ' as argument , so the program takes no command - line arguments , or ' int argc ' and ' char * * argv / char * argv [ ] ' .
2023-11-13 21:03:29 -05:00
@ C
// Main function:
2023-11-26 06:34:52 -05:00
int main ( void ) {
2023-11-13 21:03:29 -05:00
int32_t main ( int32_t argc ,
char * argv [ ] ) {
2023-12-03 07:19:51 -05:00
// Somewhere before, with using 'typedef':
2023-11-26 06:34:52 -05:00
// typedef int number_t;
// typedef char * string_t;
2023-11-13 21:03:29 -05:00
number_t main (
number_t argc ,
string_t argv [ ] ) {
@
Now , I ' ll write some basic functions that ' ll be used later in the program , so you can see that code formatting I ' ve spent whole hour writing . Don ' t mind what they do , just keep an
eye on how are they aligned and named . I ' ll reimplement some standard functions , and you can revisit them after reading few more chapters , it ' ll be more understandable then .
2023-12-03 07:19:51 -05:00
Also , what is keyword ' enum ' for ? It ' s for enumerations , and early C programming language didn ' t have it . It assigns a value to some identifier , if not specified , it ' s automatic :
@ C
// Values of A, B and C are same for these 3 enumerations.
enum { A , B , C } ;
enum { A = 0 , B = 1 , C } ;
enum { A = 0 , B = 1 , C = 2 } ;
// However, if you use:
enum { A = 1 , B , C } ;
// Then, A is 1, B is 2 and C is 3. Easy, right? Also:
enum { A , B , C = 0 , D } ;
// In this last case, A and C are 0, B and D are 1.
@
By default , it always starts from zero , if you assign some value to it ( must be integer ) , next one will be increment of previous value , if otherwise not specified .
2023-11-13 21:03:29 -05:00
*/
2023-12-03 07:19:51 -05:00
enum {
// This is completely unnecesary, but I don't care, it's a good showcase how boolean type can work, true is 1 and false is 0.
2023-11-13 21:03:29 -05:00
FALSE ,
TRUE
} ;
2023-12-03 07:19:51 -05:00
enum {
// I use these to explicitly identify character literals outside of strings.
// 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.
// I align them like this, you can do whatever you want here, I just don't like to write a lot of short lines of code...
// I align long identifiers by 40 characters + indentation width (denoted with T). I won't align next two comments, to show you the offset.
// T + 0 * 40 T + 1 * 40 T + 2 * 40 T + 3 * 40
2023-11-26 06:34:52 -05:00
// ^ ^ ^ ^
2023-11-13 21:03:29 -05:00
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 ,
CHARACTER_FORM_FEED , CHARACTER_CARRIAGE_RETURN , CHARACTER_SHIFT_OUT , CHARACTER_SHIFT_IN ,
CHARACTER_DATA_LINK_ESCAPE , CHARACTER_DEVICE_CONTROL_1 , CHARACTER_DEVICE_CONTROL_2 , CHARACTER_DEVICE_CONTROL_3 ,
CHARACTER_DEVICE_CONTROL_4 , CHARACTER_NOT_ACKNOWLEDGE , CHARACTER_SYNCHRONOUS_IDLE , CHARACTER_END_TRANSMISSION_BLOCK ,
CHARACTER_CANCEL , CHARACTER_END_MEDIUM , CHARACTER_SUBSTITUTE , CHARACTER_ESCAPE ,
CHARACTER_FILE_SEPARATOR , CHARACTER_GROUP_SEPARATOR , CHARACTER_RECORD_SEPARATOR , CHARACTER_UNIT_SEPARATOR ,
2023-11-26 06:34:52 -05:00
CHARACTER_COUNT // Not an actual ASCII table count (128), but for ending special invisible characters.
2023-11-13 21:03:29 -05:00
} ;
2023-12-03 07:19:51 -05:00
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, look above...
2023-11-13 21:03:29 -05:00
EFFECT_NORMAL , EFFECT_BOLD , EFFECT_ITALIC , EFFECT_UNDERLINE , EFFECT_BLINK , EFFECT_REVERSE ,
EFFECT_COUNT
} ;
2023-12-03 07:19:51 -05:00
enum {
// Because of text auto-completition, it's always easy to find what I want, or to use NAME_COUNT in arrays. In some cases, order matters!
2023-11-13 21:03:29 -05:00
COLOUR_GREY , COLOUR_RED , COLOUR_GREEN , COLOUR_YELLOW , COLOUR_BLUE , COLOUR_PINK , COLOUR_CYAN , COLOUR_WHITE ,
COLOUR_COUNT
} ;
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 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 * reallocate ( void * data , int size ) ;
extern void * deallocate ( void * data ) ;
extern int string_length ( char * string ) ; // We deal with strings a lot in this program, so string functions will be more important than character functions from chapter one.
2023-11-24 09:00:46 -05:00
extern int string_compare ( char * destination , char * source ) ; // See how nicely they align, right?
extern char * string_copy ( char * destination , char * source ) ;
extern char * string_concatenate ( char * destination , char * source ) ;
extern char * string_reverse ( char * string ) ; // Notice last function, we didn't align ');'...
extern int string_compare_limit ( char * destination , char * source , int limit ) ; // These ones too, it's beautiful (in my opinion), tho some consider it useless.
extern char * string_copy_limit ( char * destination , char * source , int limit ) ;
extern char * string_concatenate_limit ( char * destination , char * source , int limit ) ;
2023-12-03 07:19:51 -05:00
extern char * string_reverse_limit ( char * string , int limit ) ; // And we align the last argument in this case, use whatever you prefer.
2023-11-13 21:03:29 -05:00
extern char * string_realign ( char * string , int amount , char character ) ; // This is a simple function that realigns a string to right, we'll use it way later ahead.
2023-11-21 08:43:45 -05:00
extern int memory_compare ( void * memory , void * source , int length ) ; // We'll cover these functions later, they are more complex.
extern void memory_copy ( void * memory , void * source , int length ) ;
2023-11-13 21:03:29 -05:00
// In chapter two, we'll explain ASCII escape sequences, for now, consider this to be some black magic.
extern void terminal_clear ( void ) ; // Offset and clear terminal screen output.
extern void terminal_colour ( int colour , int effect ) ; // Set terminal character attributes.
extern void terminal_cancel ( void ) ; // Reset terminal character attributes.
extern void terminal_show_cursor ( int show ) ; // Toggle rendering of terminal cursor.
# endif