C++ has no file format in the usual sense: no header, no signature and no required extension. The standard describes a program as text that passes through nine phases of translation. The unit of compilation is the translation unit, not the file. These pages follow C++23 (ISO/IEC 14882:2024), and section names in square brackets, such as [lex.phases], are the standard’s stable names.
File names and extensions
The standard says nothing about file names. It speaks of source files and headers only, and a header need not be a file at all [cpp.include]. The extensions below are conventions that compilers and build tools have adopted.
| Extension | Holds | Notes |
|---|---|---|
.cpp .cc .cxx | Source file | Accepted as C++ by GCC, Clang and MSVC |
.c++ .cp .C | Source file | Accepted by GCC. A capital .C only means C++ on a case-sensitive file system |
.h | Header | Shared with C, so a tool cannot tell the language from the name |
.hpp .hh .hxx .h++ | Header | C++ only by convention |
.inl .ipp .tcc .tpp | Included implementation | Template or inline definitions kept apart from a header that includes them |
.ixx | Module unit | MSVC’s default for a module interface |
.cppm .ccm .cxxm .c++m | Module unit | Recognised by Clang; .cppm is its usual choice |
.ii | Preprocessed source | GCC’s and Clang’s name for C++ that has already been through the preprocessor |
Compilers also produce binary forms of module interfaces, such as Clang’s
.pcm, GCC’s .gcm and MSVC’s .ifc. These are
private to each compiler. See
Namespaces and
modules.
Translation units
A source file, together with every header and source file it includes, minus any lines skipped by conditional inclusion, is a translation unit [lex.separate]. Each translation unit is compiled alone. A linker then joins the results.
translation-unit:
[declaration-seq]
[global-module-fragment] module-declaration [declaration-seq] [private-module-fragment]
The first form is an ordinary file. The second is a module unit (C++20). In both cases, what remains after preprocessing is a series of declarations. Statements appear only inside function bodies.
// greet.hpp: the declarations that other files share
#ifndef GREET_HPP
#define GREET_HPP
#include <string>
std::string greet(const std::string& name);
#endif
// greet.cpp: one definition, in one translation unit
#include "greet.hpp"
std::string greet(const std::string& name)
{
return "Hello, " + name;
}
// main.cpp: a second translation unit that uses it
#include <iostream>
#include "greet.hpp"
int main()
{
std::cout << greet("world") << '\n';
}
greet.cpp and main.cppPhases of translation
The standard defines translation as nine phases, applied in order [lex.phases]. A compiler may merge them, as long as the result is the same.
| Phase | Name | What happens |
|---|---|---|
| 1 | Input mapping | The file’s bytes are decoded to the translation character set. Line endings become new-line characters |
| 2 | Line splicing | A byte order mark at the start is removed. Each backslash at the end of a line is deleted with the line break, joining two lines. A non-empty file that does not end in a new-line is treated as if it did |
| 3 | Tokenisation | The text is split into preprocessing tokens and white space. Each comment becomes one space. New-lines are kept |
| 4 | Preprocessing | Directives run, macros expand, _Pragma operators run and #include files go through phases 1 to 4. The directives are then deleted |
| 5 | Encoding prefixes | Adjacent string literals are given a common encoding prefix |
| 6 | Concatenation | Adjacent string literals are joined into one |
| 7 | Analysis | White space stops mattering. Preprocessing tokens become tokens, which are parsed and translated as a translation unit |
| 8 | Instantiation | Templates that are needed are instantiated, giving instantiation units |
| 9 | Linking | External references are resolved and library components are linked, giving a program image |
Consequences of this order:
- Because splicing (phase 2) comes before comments are removed (phase 3), a
//comment ending in a backslash continues onto the next line. - Because comments become spaces before directives run, a comment can appear inside a directive.
- Because concatenation (phase 6) comes after macro expansion, a macro can expand to
a string that joins its neighbours:
"a" MACRO "c". - In a raw string literal the changes made by phases 1 and 2 are undone, so a backslash at the end of a line stays in the text [lex.pptoken].
Source encoding
How a file’s bytes map to characters is implementation-defined, with one guarantee: since C++23, every compiler must accept UTF-8 source [lex.phases]. Compilers differ in their default.
| Compiler | Default source encoding | Option |
|---|---|---|
| GCC | UTF-8 | -finput-charset= |
| Clang | UTF-8 | Accepts UTF-8 only |
| MSVC | The system code page, unless the file has a byte order mark | /source-charset:, or /utf-8 for source and execution |
- A UTF-8 byte order mark at the start of a file is removed in phase 2.
- The basic character set [lex.charset] is the Latin letters, the digits,
the space and the control characters for tab, vertical tab, form feed and new-line,
and the punctuation
_ { } [ ] # ( ) < > % : ; . ? * + - / ^ & | ~ ! = , \ " '. - Any other character can be written as a universal character name:
é,\U0001F600, and since C++23\u{E9}and\N{LATIN SMALL LETTER E WITH ACUTE}. See Lexical structure. - A physical line may end in LF, CRLF or anything else the compiler maps to a new-line. Since C++23 white space between a final backslash and the line ending is ignored too.
- C++ keeps the source encoding and the literal encoding apart. The first is how the file is read; the second is what a string literal holds in the program.
Headers
A header is text pasted into a translation unit by
#include. Since it is
read once per translation unit that includes it, it normally holds only what may be
repeated across units.
| Usually in a header | Usually in a source file |
|---|---|
| Class definitions, enumerations and type aliases | Non-inline function definitions |
| Function declarations | Non-inline variable definitions |
| Templates, defined in full | Explicit template instantiation definitions |
inline functions and variables, constexpr variables | Anything meant to stay private to the file |
Include guards
A header included twice would define its classes twice. An include guard
prevents this with the preprocessor. The non-standard #pragma once does
the same and is supported by GCC, Clang and MSVC. It depends on the compiler
identifying files reliably, which symbolic links and network shares can defeat.
#ifndef LIBRARY_WIDGET_HPP
#define LIBRARY_WIDGET_HPP
class Widget { /* ... */ };
#endif
Standard library headers
C++ standard headers have no extension: <vector>,
<string>. The C library is available in two forms:
<cstdio> declares its names in namespace std, and
<stdio.h> declares them in the global namespace. Either may also
provide the names in the other place. The full list is on the
Standard library page.
Header units
Since C++20 a header can be imported rather than included:
import <vector>;. The header is compiled once as a header
unit. Unlike #include it does not see the macros of the file that
imports it, though macros it defines do reach that file. All C++ library headers can
be imported this way; the C compatibility headers need not be. See
Namespaces and
modules.
Linkage
Linkage decides whether a name in one scope can refer to the same entity as a name in another [basic.link].
| Linkage | Name is visible from | Given by |
|---|---|---|
| External | Any translation unit | Non-static functions, classes and non-const variables at namespace scope, and anything extern |
| Module (C++20) | Translation units of the same module | Declarations attached to a named module and not exported |
| Internal | Its own translation unit only | static at namespace scope, anything in an unnamed namespace, and non-template, non-volatile, non-inline const variables at namespace scope |
| None | Its own scope only | Local variables, and local classes and their members |
So const int size = 10; in a header gives each translation unit its own
variable, which is safe. int size = 10; in a header breaks the one-definition rule
as soon as two translation units include it. inline int size = 10;
(C++17) is one variable shared by all.
The one-definition rule
The one-definition rule, or ODR, limits how many definitions an entity may have [basic.def.odr].
- Within one translation unit, a variable, function, class, enumeration or template may have only one definition. Breaking this is a compile-time error.
- Across the whole program, a non-inline function or variable that is odr-used must have exactly one definition. Breaking this usually gives a link error, but no diagnostic is required.
- A class, enumeration, inline function, inline variable, template or default template argument may be defined in several translation units, as long as every definition is the same.
“The same” is strict. The definitions must be the same sequence of tokens, and each name in them must refer to the same entity. If they differ, the program is ill-formed with no diagnostic required, so it may compile, link and misbehave. This is why a macro that changes the content of a header between translation units is dangerous.
A variable is odr-used when its address or a reference to it is needed, or when its
value is read and it cannot be replaced by a constant at compile time. A function is
odr-used when it is called or its address is taken, in an expression that is potentially
evaluated. Operands of sizeof, decltype,
noexcept and most uses of typeid are not evaluated, so they
do not odr-use anything.
Program start-up
A hosted program starts at the global function main
[basic.start.main]. A freestanding one starts wherever the implementation says.
int main() { }
int main(int argc, char* argv[]) { }
intmainmay not be called by the program, overloaded, or declaredstatic,inline,constexprorconsteval. Its address may not be taken.- Falling off the end of
mainis the same asreturn 0;. This holds for no other function. argv[argc]is a null pointer.
Variables with static storage duration are initialised before main:
first by constant or zero initialisation [basic.start.static], then, for anything else,
by dynamic initialisation [basic.start.dynamic]. Within one translation unit, dynamic
initialisation follows the order of definition for most variables. Between translation units the
order is not specified, so one global’s initialiser should not rely on a global in
another file. constinit (C++20) makes a variable’s constant initialisation
a checked requirement; see Declarations.
Destruction runs in the reverse order [basic.start.term].