CCreating Header Files

Creating Header Files

As a program grows past a single file, you need a way to share function prototypes, types, and constants across multiple .c files without copy-pasting the same declarations into every one of them by hand. That is exactly the job of a header file (.h).

A Worked Example: mathutils

Splitting a small piece of functionality across three files — a header, its implementation, and a consumer — is the standard pattern for any multi-file C project.

mathutils.h — declares what exists, but defines nothing:

C
#ifndef MATHUTILS_H
#define MATHUTILS_H

/* Declaration only — no function body here. */
int add(int a, int b);

#endif /* MATHUTILS_H */

mathutils.c — includes its own header and defines the real function body:

C
#include "mathutils.h"

int add(int a, int b)
{
    return a + b;
}

main.c — includes the header to use add, without knowing or caring how it is implemented:

C
#include <stdio.h>
#include "mathutils.h"

int main(void)
{
    printf("2 + 3 = %d\n", add(2, 3));
    return 0;
}

Bash
gcc main.c mathutils.c -o app
./app
# 2 + 3 = 5

Notice that main.c never sees the body of add — only its prototype from mathutils.h. The compiler trusts the prototype while compiling main.c, and the linker later matches the call to the actual definition compiled from mathutils.c.

What Belongs in a Header

Belongs in a header

Does NOT belong in a header

Function prototypes (int add(int a, int b);)

Function bodies / definitions

Struct, union, and enum type definitions

Non-static, non-extern global variable definitions

Macro and constant definitions (#define)

Executable statements outside of macros

extern declarations of shared global variables

Include guards / #pragma once

  • A prototype tells every file that includes the header what the function's signature is, so calls can be type-checked

  • The actual function body lives in exactly one .c file, compiled exactly once into exactly one object file

  • For a shared global variable, the header holds extern int counter; and exactly one .c file holds the real int counter = 0;

Definitions in headers cause multiple-definition linker errors
If `mathutils.h` had contained the full function body instead of just the prototype, and both `main.c` and some other `.c` file included it, each of their object files would end up with its own copy of `add`'s machine code under the same symbol name. The linker would then refuse to combine them, reporting something like multiple definition of 'add'. Keeping definitions out of headers (aside from `static`/`inline` functions, which are a deliberate exception) avoids this entirely.