H File Documentation


Summary

A C/C++/Objective-C Header File is a plain-text source file holding declarations, function prototypes, struct and class definitions, constants and macros, that other source files share with an #include directive. It is part of a program’s source code, not something you run. Its MIME type is text/x-c. Read or edit a .h file in any text or code editor (VS Code, Notepad++, Vim, Xcode); it only does anything once a compiler builds it with the matching .c or .cpp files.

Technical details

FeatureValue
Full nameC/C++/Objective-C Header File
File extension.h
MIME typetext/x-c
Format typePlain-text source code (header)
LanguageC, C++ and Objective-C (also .hpp, .hxx, .hh for C++)
DeveloperC/C++ language convention; ISO/IEC standards
Introduced1972 (C language and its #include convention)
Open standardYes — text file, language is ISO-standardised
EncodingASCII / UTF-8 text (no signature)
Magic numberNone — identified by extension and content
Typical openingInclude guard (#ifndef) or #pragma once, or a comment
HoldsPrototypes, types, struct/class definitions, macros, constants
Pulled in by#include directive in .c / .cpp source
Processed byThe C/C++ preprocessor, before compilation
Compiled withGCC, Clang/LLVM, MSVC (not compiled alone)
Free editorsVS Code, Notepad++, Vim, Emacs, Xcode
Related extensions.c, .cpp, .hpp, .hxx, .cc, .cxx, .m
Specificationcppreference.com/w/cpp/header
Structure at a glance

A .h file is plain text with no magic signature; it is identified by its extension and its C-family content. It almost always opens with an include guard#ifndef NAME_H / #define NAME_H ... #endif — or the equivalent #pragma once, which stops the same declarations being inserted twice when the header is reached through several #include paths. Inside, expect #include directives, #define macros, type and struct/class declarations, and function prototypes whose bodies live in the matching .c or .cpp file.

What is a .h file?

A .h file is a C/C++/Objective-C Header File: a plain-text source file holding declarations that several source files need to share. The #include header convention dates from the earliest C, created by Dennis Ritchie at Bell Labs around 1972, and it is the mechanism that lets a program built from many source files agree on the same interfaces. A header typically contains function prototypes, type and struct definitions, class definitions in C++, enumerations, constants and preprocessor macros. Objective-C uses the same .h headers to declare its @interface classes, and some C++ projects prefer .hpp, .hxx or .hh, but the role is identical.

The key thing to understand is that a header does nothing on its own. It is not compiled directly and it is not a program. It only has meaning when a source file pulls it in with #include and a compiler then builds them together. To see why, you have to look at what the preprocessor actually does with an #include line.

The #include directive: literal text substitution

When the C or C++ preprocessor encounters an #include line, it finds the named file and copies its entire text into the current file at that point, before the compiler proper ever runs. This is pure textual substitution. There is no linking, no import of symbols, no namespace: the header’s bytes are spliced in as if you had typed them.

#include <stdio.h>   // search the system include paths
#include "config.h"   // search the current directory first, then system paths

The two bracket forms differ only in search order. Angle brackets < > tell the preprocessor to look on the system and toolchain include paths, used for standard and library headers such as <stdio.h>. Double quotes " " tell it to look in the including file’s own directory first and then fall back to the system paths, used for a project’s own headers. When the compiler reports fatal error: foo.h: No such file or directory, it means it walked every path it knows and never found foo.h; the header is missing or its folder is not on the include path.

Include guards and the double-inclusion problem

Because #include is literal text substitution, a header reached through two different paths would be pasted in twice, and redefining a struct or a type in the same translation unit is an error. Headers defend against this with an include guard:

#ifndef WIDGET_H
#define WIDGET_H

struct Widget { int id; double value; };
void widget_init(struct Widget *w);

#endif /* WIDGET_H */

The first time this header is included, WIDGET_H is not yet defined, so the preprocessor keeps the body and defines WIDGET_H. Any later inclusion in the same translation unit finds WIDGET_H already defined and skips straight to #endif, so the declarations appear exactly once. The macro name is chosen to be unique, usually derived from the file name. The common modern shorthand is #pragma once, a single line at the top of the file that tells the compiler to include the file at most once. It is not part of the ISO standard but is supported by GCC, Clang and MSVC, and it avoids the risk of two headers accidentally sharing the same guard macro.

Declaration versus definition: header versus source

The division of labour between a .h and its matching .c or .cpp is the heart of the C build model. A declaration announces that something exists and gives its shape; a definition provides the actual body or storage. Headers hold declarations so that many source files can share one interface; the source file holds the single definition.

/* math_utils.h  -- declaration (the interface) */
int add(int a, int b);

/* math_utils.c  -- definition (the implementation) */
#include "math_utils.h"
int add(int a, int b) { return a + b; }

This is the “one definition rule” in practice: the prototype can appear in a header included by hundreds of files, but the function body must be defined exactly once across the whole program, and the linker resolves each call to that single definition. Putting a full function definition in a header, and then including it from two source files, produces a duplicate-symbol link error, which is a classic beginner mistake.

The C++ exception: templates and inline functions

C++ complicates the tidy rule above. A template is not code until it is instantiated for concrete types, and the compiler needs the template’s full body visible at every point of use to generate that code. So template definitions live in headers, not in a separate source file. The same applies to functions marked inline and to constexpr functions, whose definitions are allowed in headers precisely because inline exempts them from the one-definition rule across translation units. This is why C++ headers are often much larger than C headers: they carry real implementation, not just prototypes, which is one of the reasons C++ builds can be slow.

Macros and conditional compilation in headers

Headers are also where #define macros and conditional compilation live. A macro can define a constant (#define MAX_LEN 256) or a function-like text substitution, and because the preprocessor expands macros before compilation, a macro in a header changes how every file that includes it is compiled. Conditional blocks (#ifdef, #if defined(...), #else, #endif) let one header adapt to different platforms or build configurations, for example exposing different declarations on Windows versus Linux. This power is also a caution for developers: a header can silently redefine behaviour in every dependent file, so a badly written macro in a widely included header has wide reach.

How a build actually uses a header

Putting it together, a normal build has three stages. The preprocessor expands every #include and macro, producing a single flat translation unit of pure C or C++ for each source file. The compiler turns each translation unit into an object file, checking that calls match the prototypes the headers declared. The linker then joins the object files, matching each call to the one real definition and producing an executable. Headers matter in the first two stages: they give every source file the same view of the interfaces, and they let the compiler check your calls without seeing the implementation. A header is thus a compile-time contract, shared by textual inclusion, and resolved to real code by the linker.

Frequently asked questions

What is the difference between a .h and a .c file?

The header (.h) holds declarations: prototypes, types, constants and macros that describe an interface. The .c or .cpp file holds the definitions, the actual code that does the work. Source files #include the header so they all agree on the same definitions. You compile the .c/.cpp files; you do not compile a header on its own.

What is the difference between .h and .hpp?

Both are headers and compilers treat them the same. .h is the traditional C and shared C/C++ extension; .hpp, .hxx and .hh are conventions some projects use to mark a header as C++-only. The choice is a style decision, not a technical one.

Why do I get “fatal error: xxx.h: No such file or directory”?

The compiler could not find a header your code includes. Either the file is missing, or the folder that contains it is not on the include path. Install the required library or SDK, or add its include directory to your build settings (for example with a -I flag for GCC or Clang).

References