Question
In my C course notes, many C source files begin with a line that starts with #, often near the top of the file before main().
For example:
#include <stdio.h>
int main() {
printf("Hello, World!");
return 0;
}
Why does this # appear at the start of the file, and what is its purpose in a C program?
Short Answer
By the end of this page, you will understand that the # character in C introduces a preprocessor directive, such as #include. You will learn what the C preprocessor does, why header files like stdio.h are included before main(), and how this fits into the way a C program is compiled.
Concept
In C, a line that starts with # is usually a preprocessor directive. These directives are handled by the C preprocessor before the compiler processes the actual C code.
A common example is:
#include <stdio.h>
This tells the preprocessor to include the contents of the header file stdio.h before compilation continues.
Why does that matter?
Because functions like printf() are declared in stdio.h. The compiler needs to know about printf() before you use it.
What the preprocessor does
Before your C code is compiled, it goes through an earlier stage called preprocessing. During this stage, directives beginning with # are handled. Common tasks include:
- including header files with
#include - defining constants or macros with
#define - conditionally compiling code with
#if,#ifdef, and#ifndef
Why it often appears at the top of the file
Header files are usually included at the top so the declarations they contain are available to the rest of the file.
For example, printf() is part of the standard input/output library. Without including stdio.h, the compiler may not know its correct declaration.
Important clarification
The # itself does not mean "start of program." It means "this line is for the preprocessor." Many C files begin with #include simply because they need library declarations before the rest of the code.
Mental Model
Think of the preprocessor as a preparation step before cooking.
- Your
.cfile is the recipe. - Lines starting with
#are prep instructions for the kitchen assistant. #include <stdio.h>is like saying: "Before cooking, attach this reference sheet for using the stove and utensils."
The compiler is the chef who actually cooks the meal, but first the assistant handles all the # instructions.
So the # is not part of normal C statements like if, for, or return. It is an instruction to be handled before compilation.
Syntax and Examples
The most common # directive beginners see is #include.
Basic syntax
#include <header.h>
#include "myheader.h"
Angle brackets vs quotes
#include <stdio.h>: usually used for standard or system headers#include "myheader.h": usually used for your own project headers
Example: using printf
#include <stdio.h>
int main(void) {
printf("Hello, World!\n");
return 0;
}
Why this works
#include <stdio.h>gives the compiler the declaration ofprintfmain()is the program entry pointprintf()writes text to standard output
Another preprocessor example
#define PI 3.14159
#include <stdio.h>
int main(void) {
printf("%f\n", PI);
return 0;
}
Here:
#define PI 3.14159creates a macro- before compilation, the preprocessor replaces
PIwith3.14159
Example of conditional compilation
#include <stdio.h>
#define DEBUG
int main(void) {
#ifdef DEBUG
printf("Debug mode is on\n");
#endif
printf("Program running\n");
return 0;
}
This includes the debug message only if DEBUG is defined.
Step by Step Execution
Consider this program:
#include <stdio.h>
int main(void) {
printf("Hi\n");
return 0;
}
What happens step by step
1. The preprocessor reads the file
It sees:
#include <stdio.h>
This means: include the declarations from the standard I/O header.
2. The source is expanded
The preprocessor effectively inserts the contents of stdio.h into the translation process.
You do not normally see this directly in your source file, but conceptually it is as if the compiler now has access to the declarations from that header.
3. The compiler checks main()
Now when it reaches:
printf("Hi\n");
the compiler already knows what printf is supposed to look like.
4. The compiler generates object code
If everything is valid, the code is compiled.
5. The linker connects library code
The linker connects your program to the actual implementation of library functions such as printf.
Key idea
#include does not itself print anything or run at runtime. It helps prepare the code so compilation can happen correctly.
Real World Use Cases
Preprocessor directives are used throughout real C programs.
Including standard libraries
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Used when a program needs:
- input/output
- memory allocation
- string handling
Sharing declarations across files
Large C projects often have multiple .c files and .h header files.
For example:
#include "math_utils.h"
This lets multiple source files use the same function declarations.
Enabling debug-only code
#ifdef DEBUG
printf("x = %d\n", x);
#endif
Useful for logging during development without shipping extra output in release builds.
Defining constants
#define MAX_USERS 100
Used for configuration values, array sizes, and compile-time options.
Real Codebase Usage
In real projects, developers use preprocessor directives in structured ways rather than scattering them randomly.
Common patterns
Header includes at the top of each file
Most .c files begin with all required #include lines first:
#include <stdio.h>
#include <stdlib.h>
#include "app.h"
#include "config.h"
This makes dependencies clear.
Include guards in header files
Header files often contain:
#ifndef CONFIG_H
#define CONFIG_H
int get_port(void);
#endif
This prevents the same header from being included multiple times in a problematic way.
Conditional compilation for platforms
#ifdef _WIN32
printf("Windows\n");
#else
printf("Unix-like system\n");
#endif
This helps support multiple operating systems.
Feature flags and debugging
#ifdef ENABLE_LOGGING
printf("Starting service...\n");
#endif
This allows code to be compiled differently depending on build settings.
Why this matters in codebases
Preprocessor directives help organize code, reuse declarations, control compilation, and make large programs manageable.
Common Mistakes
Beginners often see #include and understand that it is needed, but not why. That can lead to a few common mistakes.
1. Forgetting the required header
Broken code:
int main(void) {
printf("Hello\n");
return 0;
}
Problem:
printfis declared instdio.h- without the header, the compiler may warn or error
Fix:
#include <stdio.h>
int main(void) {
printf("Hello\n");
return 0;
}
2. Using # for normal C code
Broken code:
#int x = 5;
Problem:
#is only for preprocessor directives- normal variable declarations do not start with
#
3. Confusing #include <...> with #include "..."
#include <myfile.h>
#include "myfile.h"
Usually:
- use
<...>for system headers - use
"..."for your own headers
4. Thinking #include copies a library's executable code
A header file usually contains declarations, macros, and type definitions, not the full compiled implementation.
The actual function code is usually linked later.
5. Putting includes in strange places
Technically possible in some cases, but usually poor style:
int main(void) {
#include <stdio.h>
printf("Hello\n");
return 0;
}
Avoid this. Put includes at the top of the file unless you have a very specific reason.
Comparisons
| Concept | Purpose | Happens When | Example |
|---|---|---|---|
#include | Brings in declarations from a header | Preprocessing | #include <stdio.h> |
#define | Creates a macro or constant-like substitution | Preprocessing | #define SIZE 10 |
if | Makes a runtime decision | Program execution | if (x > 0) |
| Function call | Executes code in a function | Program execution | printf("Hi") |
#include vs normal C statements
#include is not a normal statement. It is handled before the compiler processes the C code.
#include vs #define
#includepulls in header content#definecreates text substitutions handled by the preprocessor
#ifdef vs if
#ifdefdecides whether code is compiled at allifdecides whether code runs while the program is executing
Cheat Sheet
#include <stdio.h> // standard header
#include "myfile.h" // your own header
#define MAX 100 // macro
#ifdef DEBUG // conditional compilation
#endif
Quick rules
#starts a preprocessor directive- preprocessor directives are handled before compilation
#includeis used to bring in header files- headers provide declarations, macros, and type definitions
- put
#includelines near the top of the file - use
<...>for standard headers - use
"..."for local project headers
Common standard headers
stdio.h→printf,scanfstdlib.h→malloc,free,exitstring.h→strlen,strcpy,strcmpmath.h→ math function declarations
Remember
#does not mean comment#includedoes not run at runtime- the compiler uses header declarations to check your code
FAQ
Why does C use #include at the top of a file?
Usually because the file needs declarations from headers before using functions, types, or macros later in the code.
What does the # symbol mean in C?
It marks a preprocessor directive. These lines are handled before the compiler processes the program.
Is #include required for printf?
Yes, printf is declared in stdio.h, so you should include that header.
Does #include copy and paste code?
Conceptually, it inserts header content during preprocessing. In practice, it is part of the compilation pipeline.
Can a C program have more than one #include line?
Yes. Most real programs include several headers.
Is # used only for #include?
No. It is also used for directives like #define, #ifdef, #if, and #endif.
Does every C file have to start with #?
No. A C file does not have to begin with a preprocessor directive, but many do because they need header files.
Mini Project
Description
Build a small C program that prints a message and uses a macro from a preprocessor directive. This project demonstrates why #include and other # directives appear at the top of C files.
Goal
Create a working C program that uses #include for printf() and #define for a constant.
Requirements
- Include the correct standard header for
printf - Define a macro for an application name or version
- Print both a greeting and the macro value
- Return
0frommain - Keep the program in a single
.cfile
Keep learning
Related questions
2D Array Loop Order and Cache Performance in C
Learn why swapping nested loops changes 2D array performance in C, using row-major memory layout, cache locality, and practical benchmarks.
Array-to-Pointer Conversion in C and C++ Explained
Learn what array-to-pointer conversion means in C and C++, how array decay works, and how it differs from a pointer to an array.
Building More Fault-Tolerant Embedded C++ Applications for Radiation-Prone ARM Systems
Learn practical C++ and compile-time techniques to reduce soft-error damage in embedded ARM systems exposed to radiation.