› Module 1: Introduction to C › 1.3 Compilation and Execution Process
M O D U L E

Module 1: Introduction to C

Origins of the language, the anatomy of a C program, and how source code becomes a running program.

1.1 History and Features of C

C was designed by Dennis Ritchie at Bell Labs (1972) to rewrite the UNIX operating system. It is a general-purpose, procedural, middle-level language — low-level enough to manipulate memory directly (via pointers), yet high-level enough to write portable, structured programs.

Before C, operating systems were written in assembly language, which was bound to specific hardware architectures. Dennis Ritchie evolved C from Ken Thompson's B language (which derived from BCPL), introducing data typing and compiler optimizations that allowed UNIX to be re-implemented portably across different computer systems with near-assembly execution speed.

Key features: simplicity and small core keyword set, direct hardware/memory access through pointers, structured programming (functions, blocks), portability across platforms, rich standard library, and being the foundation on which C++, Java, C#, and many OS kernels are built.

  • Fast execution — compiles to native machine code: Unlike interpreted or bytecode languages, C compiles directly to native CPU machine instructions without VM overhead, yielding near-zero runtime abstraction cost.
  • Modular via functions and separate compilation: Large software systems can be partitioned into independent translation units (.c and .h files), compiled separately, and linked into cohesive binaries.
  • Extensible through header files and libraries: Standard libraries (like <stdio.h> and <stdlib.h>) and third-party libraries seamlessly integrate via function declarations and preprocessor directives.
  • Statically typed with manual memory management: Variable types are determined at compile time, eliminating type-check overhead at runtime, while dynamic heap allocation gives developers exact control over memory footprint.

1.2 Structure of a C Program

Every C program follows a fixed skeleton: preprocessor directives at the top, optional global declarations, and one mandatory main() function where execution begins. Curly braces {} define blocks; every statement ends with a semicolon.

A typical C translation unit is structured into clearly defined sections:

  1. Documentation & Preprocessor Section: Header file inclusions (#include <stdio.h>) and macro definitions that tell the preprocessor to load standard prototypes and replace constants before compilation begins.
  2. Global & Type Declarations: Variables, custom structures, and function prototypes declared outside any function body so they have file-level or program-wide scope.
  3. Main Function (Entry Point): The mandatory int main() function where CPU execution starts. Returning 0 signifies successful termination to the host operating system.
  4. Function Definitions: Implementation bodies for user-defined helper functions referenced earlier by prototypes.
#include <stdio.h> // 1. Preprocessor directive
int globalVar = 10; // 2. Global declaration
int add(int a, int b); // 3. Function prototype

int main() { // 4. Entry point
  int local = 5; // 5. Local variable
  printf("%d", add(local, globalVar));
  return 0; // 6. Exit status
}

int add(int a, int b) { // 7. Function definition
  return a + b;
}

1.3 Compilation and Execution Process

A .c file is not directly executable — it passes through four stages. The Preprocessor expands directives such as #include and #define. The Compiler translates the expanded C code into assembly. The Assembler converts assembly into machine-readable object code (.o/.obj). Finally the Linker merges your object code with library code (like printf's implementation) into one executable.

Understanding each of the four distinct build pipeline phases:

  • 1. Preprocessing (gcc -E): Strips comments, expands macros (#define), and textually includes the full headers specified by #include directives. Produces a pure expanded C translation unit.
  • 2. Compilation (gcc -S): Parses syntax, performs semantic type checks, optimizes control flow, and translates high-level C code into assembly instructions (e.g., x86_64 or ARM assembly in a .s file).
  • 3. Assembly (gcc -c): Converts assembly mnemonics directly into binary machine instructions, creating a relocatable object file (.o or .obj) containing raw opcodes and symbol tables.
  • 4. Linking (gcc -o): Resolves external function references across multiple object files and links standard runtime libraries (such as libc's printf implementation) into a standalone runnable binary (a.out on Linux/macOS, .exe on Windows).
file.c (Source Code) Preprocessor expands #include, #define Compiler .c -> .s (assembly) Assembler .s -> .o (object code) Linker combines .o files + libraries a.out / .exe (Executable)
The four-stage C build pipeline: source to executable.
MODULE COMPREHENSIVE QUIZ

Module 1 Final Quiz

Test your understanding across all 3 topics of this module with interview-grade questions, tricky edge cases, and code output predictions.

Take Module 1 Final Quiz →
Yukti Mascot