瀏覽代碼

New program and more into C...

master
父節點
當前提交
34cb9268e6
共有 3 個檔案被更改,包括 194 行新增1 行删除
  1. +64
    -1
      chapter/chapter_1.h
  2. +3
    -0
      compile.sh
  3. +127
    -0
      program/program_1.c

+ 64
- 1
chapter/chapter_1.h 查看文件

@@ -262,7 +262,70 @@ Okay, that's all you really need to know about C preprocessor, since we won't us
copying and pasting a lot of code, especially external function and variable declarations. Because of that we need '#include' directive, and because of it, we need header guards,
so it's all C-hating in the end. However, we need to cover some simple macros, so you can deal with other peoples' code bases. Remember, the less "building blocks" you have, if
you learn them well, you can make anything, and you should be proud of "reinventing the wheel". If wheels weren't reinvented over and over again, then some expensive BMW would've
wooden wheels attached to it.
wooden wheels attached to it. You can also use '#define' to write entire functions, but that can lead to lot of compiler warnings for only forgetting to put one character, and it
bloats the code, so we'll show how to write them, and never use them again.

Then, as you probably noticed, comments in older C standards (K&R and ANSI) begin with "/(merged)*" and end with "*(merged)/". I put merged there, because otherwise it'd end this
comment there, and everything below it would be treated as C source code. Preprocessor modifies C source code before the compiler, so it would remove all comments, copy+paste the
content of those files we included, conditionally if we used if / ifdef/ ifndef and more. Usually syntax highlighting will be weird if you do something like this, and you'll fix
it easily, so don't worry much about it. In newer standards (C99 and forward), you can have single-line comments that beign with "//" and end with (you guessed it) new line, aka
character literal '\n' aka line feed. Again, I don't write comments at all except licence notice in my projects, but this book project is an exception. You should express what
your code does in writing it properly, not writing obfuscated code and add comments about what it does.

Otherwise, roughly speaking, you have constants, variables, functions and pointers. In the end, it all comes down to CPU instructions that use registers, immediate values and
memory addresses (REG / IMM / MEM), which we'll mention way later.

Your constants can be internal, external, defined or enumerated:

@C
static const char DELETE = '\177'; // Used in only one file, where's it declared and defined.

extern const char DELETE; // Used in C header file (.h).
const char DELETE = (char) 127; // Used in C source file (.c).

#define DELETE (0X7F) // Used where file containing this line was '#include'-d.

// Note that I consider this bad practice, since you also need to include file containing this, and it values start from 0, so in this case we need to set it to 127.
// With 'typedef'-ed example, we can provide a name for that enumeration, and use it as 'enum my_enumeration_verbose_or_same_name' or 'my_enumeration'.
// Enumerations are only useful (from my experience) when you need to '#define' a lot of values in incremental order, from 0 to some number, and they are 'int' type by default.
enum { DELETE = 127 };
typedef enum my_enumeration_verbose_or_same_name { DELETE = 127 } my_enumeration;
@

It's very similar for variables, but they can't be defined (nor should be!) or enumerated (unless you're thinking about arrays). You can have variables inside and outside
functions, those inside are called local variables, and those outside are called global variables. Global variables can make the code shorter, simpler and easier to change, but if
you or people you work with don't know what the hell they're doing, it can lead to messy code or difficult to track bugs. Just don't think that they are evil and should never be
used, because that's not the case.

Local variables (that you'll see inside my functions) are by default declared with 'auto' instead of 'static' or 'extern', but you don't need to write 'auto' before them, since
it's implicitly there. In old C language (K&R standard), they used to write code like this example below, which isn't something you should do nowdays. Also, local variables aren't
accessable or modifiable after the function ends, you'll see examples of that later.

@C
// K&R example (old C language), which would be something like following in newer standards:
output (data, size) static int output (char * data, int size) {
char * data; { (void) write (STDOUT_FILENO, (void *) data, (size_t) size * sizeof (* data));
write (1, data, size); return (0);
} }

static char * string_pointer = NULL; // Later we can modify them, use them in functions and much more, but only in file those were defined and declared.
static char * string = NULL;
// Somewhere later in the file, inside some function:
// string = calloc (1024UL, sizeof (* string));
// string = strncpy (string, "Heyo world!");
// ...
// free (string);

extern int subprogram_id; // Used in C header file (.h).
int subprogram_id = 0; // Used in C source file (.c).
// Later, any function can modify this variable with just:
// subprogram_id = 144000;
@

Functions simply are part of the program that modifies variables or execute some code that causes a side-effect, and then return a value or nothing (void). For example, our
'character_*' functions below preform some operations on operand 'character' of type 'char', without modifying it, and return some value of type 'int', and they are declared as
external with 'extern', because they are defined in another text file. In this case, our family of functions 'character_*' will return FALSE (0) or TRUE (1), depending on what
they do in their definitions, and I like to put '_is_' in functions that return boolean value (but not always).
*/

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.


+ 3
- 0
compile.sh 查看文件

@@ -16,6 +16,9 @@ gcc -g -Wall -Wextra -Wpedantic -O0 -c -o xhartae.o xhartae.c

gcc -o xhartae xhartae.o chapter/chapter_0.o chapter/chapter_1.o chapter/chapter_2.o chapter/chapter_3.o chapter/chapter_4.o chapter/chapter_5.o chapter/chapter_6.o

gcc -g -Wall -Wextra -Wpedantic -Werror -O0 -o program/program_0 program/program_0.c
gcc -g -Wall -Wextra -Wpedantic -Werror -O0 -o program/program_1 program/program_1.c

#~splint -weak -warnposix -retvalother -syntax -type chapter/chapter_0.h
#~splint -weak -warnposix -retvalother -syntax -type chapter/chapter_0.c
#~splint -weak -warnposix -retvalother -syntax -type chapter/chapter_1.h


+ 127
- 0
program/program_1.c 查看文件

@@ -0,0 +1,127 @@
/*
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.
*/

#include "../chapter/chapter_0.c"
#include "../chapter/chapter_1.c"

static void echo_separator (void) {
terminal_colour (COLOUR_GREY, EFFECT_BOLD);

echo (" | ");

terminal_cancel ();
}

static void echo_base (int character, int base, int colour, int effect) {
echo_separator ();

terminal_colour (colour, effect);

if (base == 2) {
echo (format_to_string (character, 0, base, 7, '0'));
} else if (base == 8) {
echo (format_to_string (character, 0, base, 3, '0'));
} else if (base == 16) {
echo (format_to_string (character, 0, base, 2, '0'));
} else {
echo (format_to_string (character, 0, base, 3, ' '));
}

terminal_cancel ();
}

static void echo_code (int character, int colour, int effect) {
char * code [32] = {
"NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL", "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
"DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB", "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
};

echo_separator ();

terminal_colour (colour, effect);

if (character == 0X7F) {
echo ("DEL");
} else if (character_is_invisible (character) != 0) {
echo (code [character]);
if (string_length (code [character]) == 2) {
echo (" ");
}
} else {
out (& character, 1);
echo (" ");
}

terminal_cancel ();
}

static void echo_name (int character, int colour, int effect) {
char * name [128] = {
"Null", "Start of heading", "Start of text", "End of text",
"End of transmission", "Enquiry", "Acknowledge", "Bell",
"Backspace", "Horizontal tab", "Line feed", "Vertical tab",
"Form feed", "Carriage return", "Shift out", "Shift in",
"Data link escape", "Device control 1", "Device control 2", "Device control 3",
"Device control 4", "Negative acknowledge", "Synchronous idle", "End transmission block",
"Cancel", "End of medium", "Substitute", "Escape",
"File separator", "Group separator", "Record separator", "Unit separator",
"Space", "Exclamation mark", "Speech mark", "Number sign",
"Dollar sign", "Percent", "Ampersand", "Quote",
"Open parenthesis", "Close parenthesis", "Asterisk", "Plus",
"Comma", "Minus", "Period", "Slash",
"Zero", "One", "Two", "Three",
"Four", "Five", "Six", "Seven",
"Eight", "Nine", "Colon", "Semicolon",
"Open angled bracket", "Equal", "Close angled bracket", "Question mark",
"At sign", "Uppercase A", "Uppercase B", "Uppercase C",
"Uppercase D", "Uppercase E", "Uppercase F", "Uppercase G",
"Uppercase H", "Uppercase I", "Uppercase J", "Uppercase K",
"Uppercase L", "Uppercase M", "Uppercase N", "Uppercase O",
"Uppercase P", "Uppercase Q", "Uppercase R", "Uppercase S",
"Uppercase T", "Uppercase U", "Uppercase V", "Uppercase W",
"Uppercase X", "Uppercase Y", "Uppercase Z", "Opening bracket",
"Backslash", "Closing bracket", "Caret", "Underscore",
"Grave", "Lowercase a", "Lowercase b", "Lowercase c",
"Lowercase d", "Lowercase e", "Lowercase f", "Lowercase g",
"Lowercase h", "Lowercase i", "Lowercase j", "Lowercase k",
"Lowercase l", "Lowercase m", "Lowercase n", "Lowercase o",
"Lowercase p", "Lowercase q", "Lowercase r", "Lowercase s",
"Lowercase t", "Lowercase u", "Lowercase v", "Lowercase w",
"Lowercase x", "Lowercase y", "Lowercase z", "Opening brace",
"Vertical bar", "Closing brace", "Tilde", "Delete"
};

echo_separator ();

terminal_colour (colour, effect);

echo (name [character]);

out (" ", 40 - string_length (name [character]));

terminal_cancel ();
}

int main (void) {
int character;

for (character = 0; character != 128; ++character) {
echo_base (character, 2, COLOUR_BLUE, EFFECT_NORMAL);
echo_base (character, 8, COLOUR_CYAN, EFFECT_NORMAL);
echo_base (character, 10, COLOUR_CYAN, EFFECT_ITALIC);
echo_base (character, 16, COLOUR_CYAN, EFFECT_BOLD);
echo_code (character, COLOUR_PINK, EFFECT_BOLD);
echo_name (character, COLOUR_WHITE, EFFECT_NORMAL);

if ((character % 2) != 0) {
echo ("\n");
}
}

return (EXIT_SUCCESS);
}

Loading…
取消
儲存