The C Programming Language

A Practical Approach

Part I

Introduction to C and Toolchain

What C is and where it fits in modern software

C is a general-purpose programming language that was developed in the 1970s by Dennis Ritchie at Bell Laboratories. It is known for its efficiency, speed, and low-level control over hardware, making it a popular choice for system programming, embedded systems, and operating systems development. C is also widely used in various application domains, such as graphics, networking, and scientific computing. Concerned with the production of software, C has few built-in libraries, data types and structures. But that's is a vow of trust to the programmers, that they have to start something from scratch, or use bad documented and complex third-party libraries, that would surprise me if you compile it without errors in your machine. While I was making my Genetic Algorithm's API to optimize antenna arrays many years ago, it was impossible to find a good third-party library, so I designed one, that was simple to use and maintain, and allowed many types of optimization problems. I added a complete .txt documentation describing each class and function (it was programmed in C++). Apart from the "starting from scratch", that annoys many modern programmers, C provide a complete access to memory and system resources. I experienced Rust, a few months ago, and is a pretty good language, but programming in C is easier given its reduced set of keywords. I would recommend C if you are going to start something from a-new, and if you have plenty of patience to deal with errors handling, and memory management. Otherwise, C is just an old programming language with few resources, that annoys many people who doesn't understand it main objective. Fast and small programs, compared to Java, or other more recently designed languages. The toolchain is composed of four steps: preprocessing, compiling, assembling, and linking. I prefer to use a Linux machine with GCC compiler tools, such as gcc, make, gdb, etc. with a simple text editor like emacs, nano, vim, etc. No expensive IDEs for me. I tried VS Code, but it rapidly add up code that you don't need, and don't want, provided by AI, that helps you to acceletate development and shipping of software, that you actually don't understand how it works. MY ADVICE: keep things simple, don't use AI generated code, and you won't be disappointed to throw away all your project, because AI inserted a buggy code, that she can't fix it, without adding more code that you don't know how it works, and cannot document.

Compilation Model: Preprocessing, Compiling, Assembling, and Linking

There are many C compilers avaiable today. The GCC and Clang are the most popular. I use GCC since I started to program on Linux machines, as well as other GNU.

Preprocessing

Preprocessing occurs before the actual compilation process. It involves the expansion of macros, inclusion of header files, and conditional compilation directives. The preprocessor is responsible for handling the `#include`, `#define`, and `#if` directives.

The following code examplifies the preprocessor usage.

        
          #include < stdio.h >
          #define DEBUG 1
          #define SQUARE(X) (X*X)

          int main (){
	            int d = 16;
	            #if DEBUG
		            printf("\n Debugging Code...");
		            printf("\n squaring %d = %d\n", d, SQUARE(d));
	            #else
		             printf("\n Normal Code...");
	            #endif
	            return 0;
            }
        
      

The first preprocessor directive is the #include, that loads header files into the code. Header files .h contains definitions of functions and macros, that are used by the .c files, containing the actual implementation of the functions.

The #if, #else and #endif only executes if DEBUG is defined and different from 0. Finally, the function main() returns 0. Main always returns 0, to say to the OS that everything went well.

main() function is the entry point of the program, where the execution starts. every program has to have a main() function that initiates the program execution.

Then we define a macro called DEBUG that will mark the debugging code. Next SQUARE is a function macro that is not compiled with the code, but is transformed into assembly code, and linked afterwards.

Compiling

Compiling is the process of converting a source code into target (or object) machine code. Compilers have a front-end, and a back-end, and some have a middle-end too, where optmization and intermediary code is generated. The front-end is composed of a lexer, a parser, and a semantic analyzer. The lexer creates a stream of bytes, or characters, that are classified into tokens.

I'll recommend that you use GNU/gcc compiler and gdb debugger. For building your system use make. As an editor I chose Zed, which is programmed in Rust and for that reason is safe and fast enough.

NOTE: Feel free to use your windows machine too. There are many IDEs that can be as useful as annoying.
For other compiler's options we have clang, that I particularly don't know much about.

        With gcc, compile the code with: 
gcc [files] -o [program]
run with:
./program
This should work for all the programs we have in this book.

Debugging

Debugging takes time and patience. The simplest way to debug a program is by using messages concerning the code with if-else and printf combination. But, if you need a professional debugger, you can use gdb. gdb is a command line debugger that can be used to debug C programs. It is a powerful tool that can be used to debug complex programs. It takes some time to learn, but worth it. On Windows, you can use Visual Studio or Visual Studio Code with the C/C++ extension. They all provide a debugging feature, that I particularly never needed to use.

Other tools

To make your life easier, we'll use make with a Makefile to build our examples, here. The use of make gets interesting when you need to use other programs to build your code, that can be called in make to build it. There are other tools, such as c, such as CMake and Autotools. You can use what you prefer, but make is a good starting point.