Create a program – C

The process of creating C programs is a process starting with writing the code and executing the binary, which can be divided into 6 steps. These steps group into three: writing the code (1), building the program (2..4) and running the program(5..6). The steps are as follows:

  1. Writing source code
  2. Preprocessing
  3. Compiling
  4. Linking
  5. Loading
  6. Executing
Process of creating C program

NB! When referring to type, it has to be typed into terminal while having the current working directory where the source code is.

Writing source code

Writing the source code is the main job of the programmer. This is done within an IDE (Integrated Development Environment) when a programmer writes text with a specific syntax, which will later on be turned into a binary executable (See next steps). Code is essentially text which will be saved as .c and .h files (for C code files). By doing so the IDE will know to highlight language specific keywords and strings to ease the writing and reading of the code.

Writing the code will be described in other posts regarding C language.

After finishing with code the next step will be building the program, which will be initiated  by the user, telling the C compiler to start the creation process of binary executable (your program, which can be run).

In this example we use the following code (hello.c):

#include <stdio.h>

int main(void) {

    puts("CodingMeta");

    return 0;
}

To initiate the whole build process one must execute the compiler and provide the source code which has to be built. In this case we will use the GCC (GNU C Compiler) and write: gcc hello.c

This will produce a binary file (executable) with a name a.out after the linking step.

Preprocessing

Preprocessing is the first step in compilation. In this step preprocessor will process the source files (.c and .h) before the next step.

Preprocessor directives (lines starting with #, such as include, define, etc.) will be processed in this stage. These directives form a simple macro language with its own syntax. This serves a purpose of having less repetition within source code (e.g. #define), conditionally compile code blocks (e.g. #if, #ifdef, etc.).

This step does not require any input from the programmer, however if programmer wants to see the output of this step, it is possbile to do so by typing the following command: gcc -E hello.c

The result of this command however is printed on the screen, if one desires to save it into a file, one should use stream redirection to save it to a file e.g. : gcc -E hello.c > preprocessor.txt

Output of that command [ Link ]. To understand the output see [ 3 ].

Compiling

This process will result with the preprocessed code being turned into architecture specific assembly code and then to object code (binary instructions).

First step in compiling process is creating assembly code specific to target processor architecture. This code is the last form of code which is still human readable with seemingly non sense making keywords structured in a specific way. C language is built for the reason that the programmer would have abstractions which allow writing more human readable code and then having the compiler do the translation to assembly language. To see the different instructions in assembly language in x86 architecture see [ 4 ].

To see the output of translating the preprocessed C code to assembly language can be seen by typing: gcc -S hello.c

   .file	"hello.c"
   .section	.rodata
.LC0:
   .string	"CodingMeta"
   .text
   .globl	main
   .type	main, @function
main:
.LFB0:
   .cfi_startproc
   pushq	%rbp
   .cfi_def_cfa_offset 16
   .cfi_offset 6, -16
   movq	%rsp, %rbp
   .cfi_def_cfa_register 6
   movl	$.LC0, %edi
   call	puts
   movl	$0, %eax
   popq	%rbp
   .cfi_def_cfa 7, 8
   ret
   .cfi_endproc
.LFE0:
   .size	main, .-main
   .ident	"GCC: (Ubuntu 5.4.1-2ubuntu1~16.04) 5.4.1 20160904"
   .section	.note.GNU-stack,"",@progbits

After creating the assembly code the assembler is being invoked, which will turn the assembly code into machine code and store it in an object file (.o). This is a set of instructions which can be run by the target processor. Some compilers support the usage of an integrated assembler, which will generate machine code directly.

To see the output of assembled assembly code (machine code or object code) type : gcc -c hello.c

Because the output of this stage is a binary file (hello.o), it is not human readable. To view the contents (hexadecimal values) with ASCII characters on the side, you can use the command (works in linux)hexdump -C hello.o [ Link ].

Linking

After creating the object code from your source file, the instructions must be linked together:

  • Your programs object code
  • Library object codes (.lib, .a) – static libraries

Most common library which is linked to your program is math library, which is necessary when the program includes math.h header. The libraries which are supposed to be linked with the program can be specified with a flag -l[library name] , for example: gcc source.c -lm , where m is math library.

After linking step your program is created and you get a binary file. This program can now be executed.

Loading

When running a program, the executable code is loaded to memory with shared libraries (.dll, .so files). This ensures that the program is able to call the necessary functions from libraries whenever it is required.

Usage of shared libraries enables the functionality of updating the library function logic by updating the library file, whereas the API (Application Programming Interface) of those functions should remain the same. This does not require recompiling user program.

This step is executed by the Operating System.

Executing

This is the final step in creating a program – executing the compiled program. At this stage the program is running and is being executed according to the input and performing tasks which are described in the source code.

To execute the binary file (a.out) which was created by typing: gcc hello.c , we must navigate to the directory where the program is and type: ./a.out (works on linux).

This will then do the Loading step and execute the program, which in this case outpus CodingMeta in terminal.

Resources

  1. The four stages of Compiling a C program [ Link ]
  2. C programming tutorial [ Link ]
  3. Preprocessor Output [ Link ]
  4. x86 instruction set [ Link ]

2 thoughts on “Create a program – C

Comments are closed.