100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
C

Header Files in C

Learn how C header files work, how to write and include your own, and how include guards prevent multiple-inclusion errors.

File Handling & PreprocessorIntermediate10 min readJul 7, 2026
Analogies

1. Introduction

A header file in C (conventionally with a .h extension) contains declarations — function prototypes, macro definitions, type definitions, and extern variable declarations — that are meant to be shared across multiple source (.c) files. Rather than repeating the same declarations in every file that needs them, you write them once in a header and #include it wherever needed. This is the foundation of modular C programs: a library exposes its public interface through headers while keeping implementation details in separate .c files, and standard headers like stdio.h and stdlib.h expose the declarations for the C standard library functions you use every day.

🏏

Cricket analogy: A header file is like a team's official playing conditions document shared with every match official and broadcaster, written once so umpires, scorers, and commentators all reference the same rules without re-explaining them each match.

2. Syntax

c
/* mathutils.h */
#ifndef MATHUTILS_H
#define MATHUTILS_H

int add(int a, int b);
int subtract(int a, int b);

#endif /* MATHUTILS_H */

/* usage in another file */
#include "mathutils.h"
#include <stdio.h>

3. Explanation

A header file typically declares (but does not define/implement) functions using prototypes, so the compiler knows their signatures when they are called from a different .c file than the one that defines them; the actual function bodies live in a corresponding .c source file (e.g., mathutils.c) which is compiled and linked separately. Headers also commonly hold #define constants, typedef declarations, struct/enum definitions, and extern declarations for global variables shared across files. When a header is #include'd, the preprocessor literally pastes its text into the including file at that point — if the same header is included more than once in a single translation unit (directly or indirectly through other headers), its declarations would be duplicated, which the compiler rejects for things like struct or typedef redefinitions. The standard fix is the include guard pattern: wrapping the entire header content in #ifndef UNIQUE_MACRO, #define UNIQUE_MACRO, and a matching #endif. The first time the header is included, UNIQUE_MACRO is undefined, so the body is processed and the macro gets defined; on any subsequent inclusion within the same translation unit, the #ifndef check fails and the body is skipped entirely, preventing duplicate-declaration errors. Many compilers also support #pragma once as a non-standard shorthand for the same effect.

🏏

Cricket analogy: Declaring a bowler's pace and style on the team sheet without describing every delivery is like a header's function prototypes; the include guard is like ensuring the team sheet isn't accidentally printed twice in the same program, which would create a duplicate roster entry the scorer would reject.

4. Example

c
/* shapes.h */
#ifndef SHAPES_H
#define SHAPES_H

typedef struct {
    double radius;
} Circle;

double circle_area(Circle c);

#endif /* SHAPES_H */

/* shapes.c */
#include "shapes.h"
#define PI 3.14159

double circle_area(Circle c) {
    return PI * c.radius * c.radius;
}

/* main.c */
#include <stdio.h>
#include "shapes.h"

int main(void) {
    Circle c = { .radius = 3.0 };
    printf("Area = %.2f\n", circle_area(c));
    return 0;
}

5. Output

text
Area = 28.27

Omitting include guards (#ifndef/#define/#endif) is a common source of multiple-inclusion errors: if a header defines a struct or typedef and gets pulled in twice into the same translation unit (for example, header A includes header B, and the .c file also includes header B directly), the compiler will report redefinition errors. Always wrap every header's content in a unique include guard, or use #pragma once where supported, to make the header safe to include multiple times.

Name your include guard macro after the file path/name to keep it unique across a large project, e.g. MYLIB_SHAPES_H for mylib/shapes.h — generic guard names like HEADER_H risk clashing with an identically named guard in an unrelated header.

6. Key Takeaways

  • Header files hold shared declarations (function prototypes, macros, typedefs, struct/enum definitions) — not full function implementations.
  • #include textually pastes the header's contents into the including file at that point.
  • Include guards (#ifndef/#define/#endif) prevent duplicate declarations when a header is included more than once in a translation unit.
  • Function definitions belong in a matching .c file, which is compiled separately and linked with files that include the header.
  • Use unique, descriptive guard macro names to avoid clashes across a large codebase.

Practice what you learned

Was this page helpful?

Topics covered

#CProgrammingStudyNotes#Programming#HeaderFilesInC#Header#Files#Syntax#Explanation#StudyNotes#SkillVeris#ExamPrep