Difference between cc and cc -c when compiling a C program

Learn difference between cc and cc -c when compiling a c program with practical examples, diagrams, and best practices. Covers c, cc development techniques with visual explanations.

Understanding cc vs. cc -c in C Compilation

Hero image for Difference between cc and cc -c when compiling a C program

Explore the fundamental differences between cc and cc -c commands when compiling C programs, and how they impact the compilation process and output files.

When working with C programming, the cc command (often an alias for gcc or clang) is your primary tool for compiling source code. However, you'll frequently encounter two distinct usages: cc filename.c and cc -c filename.c. While both initiate the compilation process, they serve different purposes and produce different outputs. Understanding this distinction is crucial for managing larger projects, optimizing build times, and debugging compilation issues.

The Full Compilation Process: cc filename.c

When you execute cc filename.c without any additional flags, you are instructing the compiler driver to perform the entire compilation process, from source code to an executable program. This involves four main stages:

  1. Preprocessing: The preprocessor (cpp) handles directives like #include, #define, and conditional compilation (#ifdef). It expands macros and includes header files, producing a single, expanded source file (often with a .i extension).
  2. Compilation: The compiler (cc1 for GCC) takes the preprocessed code and translates it into assembly language specific to your target architecture. This stage checks for syntax errors and generates an assembly file (e.g., filename.s).
  3. Assembly: The assembler (as) converts the assembly code into machine code, creating an object file (e.g., filename.o). Object files contain machine instructions but are not yet executable because they might have unresolved references to functions or variables defined in other files or libraries.
  4. Linking: The linker (ld) takes one or more object files, along with any necessary libraries, and resolves all external references. It combines them into a single, executable program. If no output filename is specified, the default executable name is a.out on Unix-like systems.
flowchart TD
    A[C Source Code (.c)] --> B{Preprocessor (cpp)}
    B --> C[Preprocessed Code (.i)]
    C --> D{Compiler (cc1)}
    D --> E[Assembly Code (.s)]
    E --> F{Assembler (as)}
    F --> G[Object File (.o)]
    G --> H{Linker (ld)}
    H --> I[Executable Program (a.out)]
    style A fill:#f9f,stroke:#333,stroke-width:2px
    style I fill:#9f9,stroke:#333,stroke-width:2px

The complete C compilation and linking process.

cc myprogram.c -o myprogram
./myprogram

Compiling and running a C program using cc.

Compiling to Object Files Only: cc -c filename.c

The cc -c filename.c command instructs the compiler to stop after the assembly stage, producing an object file (.o extension) but not performing the linking step. This means the output is not an executable program, but rather a compiled module that can be linked with other object files or libraries later.

This approach is particularly useful in several scenarios:

  • Modular Compilation: In large projects, you often have multiple source files. Compiling each file individually to an object file allows you to recompile only the files that have changed, saving significant time during development.
  • Creating Libraries: When building static (.a) or shared (.so or .dylib) libraries, you first compile source files into object files, and then use a separate tool (like ar for static libraries or ld for shared libraries) to combine them.
  • Separation of Concerns: It enforces a clear separation between compilation (source to object) and linking (objects to executable), which can be beneficial for complex build systems.
flowchart TD
    A[C Source Code (.c)] --> B{Preprocessor (cpp)}
    B --> C[Preprocessed Code (.i)]
    C --> D{Compiler (cc1)}
    D --> E[Assembly Code (.s)]
    E --> F{Assembler (as)}
    F --> G[Object File (.o)]
    style A fill:#f9f,stroke:#333,stroke-width:2px
    style G fill:#9cf,stroke:#333,stroke-width:2px

The compilation process when using cc -c.

cc -c main.c
cc -c functions.c
ls *.o
# Output: main.o  functions.o

# Later, link them together to create an executable
cc main.o functions.o -o myprogram
./myprogram

Compiling multiple source files to object files and then linking them.

Key Differences Summarized

The table below highlights the core distinctions between cc and cc -c.

Hero image for Difference between cc and cc -c when compiling a C program

Comparison of cc and cc -c.

In summary, cc performs the entire compilation and linking process to create an executable, while cc -c stops after generating an object file. Both are essential tools in C development, each serving a distinct and important role in the software build lifecycle.