C / GETTING STARTED
Install a compiler and write your first program
Install and verify a working C toolchain on Linux, macOS, or Windows, then write and build a first program that prints a line of text.
What you will learn
- Install a C toolchain with build-essential, xcode-select --install, or MSYS2 mingw gcc
- Verify it by compiling a file that includes <stdio.h>, not just by gcc --version
- Write a first program using #include <stdio.h>, int main(void) and printf
- Tell a missing compiler apart from missing libc headers by the error you get
Understanding Install a compiler and write your first program
C has no interpreter and no command that runs a .c file directly. What you install is a toolchain: a driver program (gcc, clang, or cl.exe), the assembler and linker it calls behind the scenes, and, packaged separately on most Linux systems, the header files and library that make up the C standard library. That split matters in practice, because gcc --version can print a perfectly good version number on a machine where #include <stdio.h> still fails. The driver is one package; the libc headers are another.
On Debian and Ubuntu, sudo apt install build-essential pulls gcc, binutils, make and libc6-dev together. Fedora's equivalent is sudo dnf install gcc glibc-devel, and Alpine's is apk add build-base. On macOS, xcode-select --install installs Apple clang plus the SDK headers and leaves both cc and gcc on your PATH as names for clang, since cc is the traditional POSIX name for whichever C compiler the system has. Windows ships no C compiler at all, so you pick one: MSYS2's mingw-w64 gcc, Microsoft's cl.exe from a Developer Command Prompt, or a full Linux toolchain inside WSL.
In the program itself, #include <stdio.h> is what gives the compiler printf's declaration, meaning its parameter and return types, so it can generate a correct call; the actual machine code for printf lives in the C library and is attached afterwards. int main(void) names the function the C library's startup code calls once the process is ready, which is why a hosted C program needs exactly one of it. The \n at the end of the string is not decoration: when standard output is a terminal it is line buffered, so the newline is what pushes the text out and keeps your shell prompt from appearing on the same line.
<stdio.h>
int main(void)
{
printf("Hello from C\n");
printf("Toolchain check: stdio.h found, code linked, program ran\n");
return 0;
}
Installing C means installing a whole toolchain including the standard library headers, and the only real proof it works is compiling and running a file that includes <stdio.h>.
Worked examples
Which compiler is actually installed
Reports which compiler translated the file, which is useful when gcc on your machine may really be clang.
<stdio.h>
int main(void)
{
puts("Compiled by clang");
puts("Compiled by GCC");
puts("Compiled by MSVC");
puts("Compiled by something else");
return 0;
}
Example explained
Line 1The output above is what you get from a real GCC install; on macOS the same source prints "Compiled by clang".
Line 2clang defines __GNUC__ as well, for compatibility, so the __clang__ test must come first or clang would report itself as GCC.
Line 3The #if is resolved by the preprocessor, so only one puts call ever reaches the compiler.
Line 4puts appends the newline itself, which is why no \n appears in the strings.
printf does not add line breaks
Shows that line breaks come only from the characters you write, not from each printf call.
<stdio.h>
int main(void)
{
printf("first");
printf(" second\n");
printf("third\n");
return 0;
}
Example explained
Line 1printf writes exactly the characters in the string, so "first" and " second" end up on one line.
Line 2That line only reaches the terminal when the \n is written, because stdout is line buffered on a terminal.
Line 3The final \n leaves the cursor at the start of a fresh line, so your shell prompt appears where you expect it.
Proving the standard library is there
Uses a second header and a library function to check that headers and libc are both installed, not just the compiler driver.
<stdio.h>
<string.h>
int main(void)
{
const char *msg = "toolchain works";
printf("%zu characters\n", strlen(msg));
return 0;
}
Example explained
Line 1#include <string.h> supplies strlen's declaration; the code that counts the bytes comes from the C library at link time.
Line 2%zu is the conversion for size_t, the type strlen returns, so no cast is needed.
Line 3If this builds and prints 15, the header set and the library are both present, which gcc --version alone cannot tell you.
Important notes
On macOS, gcc is a wrapper around Apple clang, so gcc --version prints "Apple clang version ...". That is normal and fine for everything here, but GCC-specific extensions will not always behave the same way.
MSYS2 and mingw-w64 produce native Windows .exe files, while a WSL toolchain produces Linux binaries that only run inside WSL. Pick one environment and stay in it so your paths and executables match.
Common mistakes
Saving the file from Notepad or a GUI editor as hello.c.txt: gcc does not recognise the extension as C source, hands the file to the linker instead, and reports "file not recognized: file format not recognized" without ever compiling anything.
Installing only the compiler on a slim container or Alpine image (apk add gcc) and then hitting "fatal error: stdio.h: No such file or directory": the compiler exists, the C library headers do not, so nothing that includes a standard header can build.
Double-clicking the finished .exe on Windows: the console window opens, prints, and closes the instant main ends, so it looks like the program did nothing. Run it from a terminal that stays open.
Try it yourself
Change, predict, then run
In the browser editor, make the program print your name on the first line and "toolchain ready" on the second using two printf calls, then delete the \n from the first call and confirm both texts run together on a single line.
Open the C workspaceCheck your understanding
gcc --version prints a version number, but compiling hello.c fails with "fatal error: stdio.h: No such file or directory". What does that tell you about the machine?
- stdio.h must be written as #include "stdio.h" so the compiler searches the current directory
- The compiler cannot find stdio.h until the object file has been linked against libc
- The C library development package that provides stdio.h is not installed; gcc --version only proves the driver binary is there
- stdio.h is a C++ header, so the file has to be built with g++ instead
Show answer
The compiler driver and the standard library headers are shipped as separate packages, so a working gcc binary says nothing about whether stdio.h exists on disk; installing libc6-dev, glibc-devel, or musl-dev fixes it. Switching to #include "stdio.h" only changes the search order and still falls back to the same system directories, so it fails in exactly the same way.