A header describes an interface shared by translation units. It normally contains function declarations, type definitions, constants, and carefully designed macros; executable definitions usually belong in one .c file.
Including a header copies its preprocessed contents into the current source file. Guards prevent repeat inclusion inside one translation unit, but they do not repair multiple externally linked definitions placed in a header.
A .h file publishes declarations that callers need. A .c file supplies private helpers and the definitions that perform the work. Keeping this boundary narrow reduces rebuilds and lets implementations change without rewriting callers.
| Syntax | Meaning |
|---|---|
| #include <stdio.h> | System header - searched in compiler's include path |
| #include "myheader.h" | Custom header - searched in current directory first |
| Header | Purpose | Key Functions |
|---|---|---|
| <stdio.h> | Input/Output | printf, scanf, fopen, fclose, fprintf |
| <stdlib.h> | General utilities | malloc, free, atoi, exit, rand, qsort |
| <string.h> | String operations | strlen, strcpy, strcat, strcmp, memcpy |
| <math.h> | Math functions | sqrt, pow, sin, cos, floor, ceil, fabs |
| <time.h> | Date and time | time, clock, difftime, strftime |
| <ctype.h> | Character classification | isalpha, isdigit, toupper, tolower |
| <errno.h> | Error codes | errno, perror, strerror |
| <limits.h> | Type limits | INT_MAX, INT_MIN, CHAR_MAX, LONG_MAX |
| <stdbool.h> | Boolean type (C99) | bool, true, false |
| <stdint.h> | Fixed-width integers | int8_t, uint32_t, int64_t |
The key rule: always use include guards (or #pragma once) to prevent a header from being included multiple times in the same translation unit.
// mathutils.h - declarations only (no implementation)
#ifndef MATHUTILS_H // include guard: if not already defined...
#define MATHUTILS_H // ...define it (prevents double inclusion)
// Constants
#define PI 3.14159265358979
// Function prototypes (declarations)
int add(int a, int b);
int subtract(int a, int b);
double circleArea(double radius);
int isPrime(int n);
#endif // MATHUTILS_H
// mathutils.c - implementations
#include "mathutils.h" // include our own header
int add(int a, int b) {
return a + b;
}
int subtract(int a, int b) {
return a - b;
}
double circleArea(double radius) {
return PI * radius * radius;
}
int isPrime(int n) {
if (n < 2) return 0;
for (int i = 2; i * i <= n; i++) {
if (n % i == 0) return 0;
}
return 1;
}
// main.c - uses the mathutils module
#include <stdio.h>
#include "mathutils.h" // our custom header
int main() {
printf("add(3, 4) = %d\n", add(3, 4));
printf("subtract(10, 3) = %d\n", subtract(10, 3));
printf("circleArea(5.0) = %.2f\n", circleArea(5.0));
printf("isPrime(17) = %d\n", isPrime(17));
printf("isPrime(18) = %d\n", isPrime(18));
printf("PI = %.5f\n", PI);
return 0;
}
// Compile: gcc main.c mathutils.c -o app
// Output:
// add(3, 4) = 7
// subtract(10, 3) = 7
// circleArea(5.0) = 78.54
// isPrime(17) = 1
// isPrime(18) = 0
// PI = 3.14159
| Method | Syntax | Portability | Notes |
|---|---|---|---|
| Include guards | #ifndef / #define / #endif | Standard C - works everywhere | Verbose but guaranteed |
| #pragma once | #pragma once | Supported by GCC, Clang, MSVC | Simpler, not in C standard |
A declaration tells the compiler a name and type. A definition allocates an object or supplies a function body. Compatible declarations may appear in several translation units, but an externally linked object or function normally needs exactly one definition in the linked program.
| Header-Safe Item | Usually Keep in .c |
|---|---|
| Function prototype | Non-inline function body |
| struct, union, enum, and typedef definitions | Private helper definitions |
| extern object declaration | The one external object definition |
| Preprocessor or enum constant | Mutable module state |
| Small static inline helper | Large implementation logic |
An extern declaration refers to a definition with external linkage elsewhere. A file-scope static name has internal linkage and remains private to that translation unit. A static inline function in a header creates an internal helper for each translation unit and should remain small.
A public header should compile when included first in an otherwise minimal source file. Include the headers needed by its own declarations instead of relying on an unrelated transitive include, but avoid exposing implementation-only dependencies.
Try this next
0 of 2 completed
Explore 500+ free tutorials across 20+ languages and frameworks.