GET /posts/gcc-main-c200 OK

What happens when you type gcc main.c

Originally published on LinkedIn.

Before we talk about what happens when we type this command to compile a C program:

gcc main.c

let's first talk about what compiling a program means.

Compiling programs

A computer doesn't understand any language except machine language (0s and 1s). So when we write a program in a higher-level language like C or C++, we need a special program that translates our statements into a form the computer can understand. That program is called a compiler.

A compiler is a software program that analyzes a program written in a particular language and translates it into a form that can run on your particular computer system.

The GCC compiler

GCC, the GNU Compiler Collection, is a program commonly used to compile C. It started as a compiler for C only, but it now supports many other languages, including C++, Objective-C, Ada, Go, Fortran and D.

It's also known as gcc in lowercase, which is the command you type. It translates a C file into an executable in machine language that the computer can run.

In this article we'll focus on compiling a C file with gcc.

Compiling a C program: behind the scenes

A C program goes through these steps during compilation:

Diagram of compiling a C program: edit, compile and assemble, link with libraries, execute a.out, and check the results

The four stages inside gcc

When you type gcc main.c, gcc actually runs four stages, one after another. You can stop it after each stage to see what it produced:

StageWhat it doesStop here withOutput
1. PreprocessorReplaces each #include with that file's contents, expands #define macros and removes commentsgcc -E main.cExpanded C code, printed to the screen
2. CompilerTranslates the C code into assemblygcc -S main.cmain.s
3. AssemblerTranslates the assembly into machine codegcc -c main.cmain.o (an object file)
4. LinkerJoins your object file with the libraries it uses, like the code behind printfgcc main.ca.out (the executable)

Knowing the stages helps you read error messages. implicit declaration of function comes from the compiler: it hasn't seen a declaration of that function. undefined reference to comes from the linker: it knows the name, but can't find the code.

Trying it out

To see what happens when we type gcc main.c, let's open the terminal and create a file named hello.c with a simple program that prints Hello World!:

vi hello.c
#include <stdio.h>

int main(void)
{
	/* this prints "Hello World" */
	printf("Hello World!");
	return (0);
}

Before compiling, there's only one file in the folder:

$ ls
hello.c

Now let's compile it:

$ gcc hello.c

The result is stored in a new file, ready to run. On Unix-like systems, this file is called a.out by default. On Windows, the executable usually has the same name as the source file, with .c replaced by .exe.

$ ls
a.out  hello.c

You can choose the name yourself with -o, for example gcc hello.c -o hello.

Now let's run a.out:

$ ./a.out
Hello World!%

Finally, Hello World! is printed.

The % right after the text isn't part of the output. The program doesn't print a newline (\n) at the end, so zsh adds a % to show that the last line ended without one. Changing the line to printf("Hello World!\n"); makes it disappear.
Note for Mac users: on macOS, the gcc command is usually Apple's Clang compiler under the same name. Run gcc --version to check. The four stages and the flags above work the same way.

Sources

← all posts