Директива #include обрабатывается препроцессором до компиляции и работает буквально: содержимое указанного файла подставляется на место директивы. Никакой «загрузки библиотеки» не происходит — это текстовая вставка, а не команда «во время запуска открыть другой файл с кодом».

#include <iostream>   // системный заголовок: ищется в путях компилятора
#include "my_code.h"  // свой: сначала ищется рядом с текущим файлом

Угловые скобки — для стандартной библиотеки и внешних библиотек, кавычки — для собственных файлов проекта. Конкретные правила поиска зависят от инструментов и настроек сборки.

Увидеть результат подстановки можно своими глазами: после g++ -E main.cpp вместо десятка написанных строк окажутся тысячи строк из подключённых заголовков. Заголовки сами подключают другие заголовки, поэтому разрастание нормально. См. Компиляция и сборка.

Что ещё умеет препроцессор

Кроме подключения файлов — макроподстановки:

#define TWO 2
 
int main() {
  return TWO + TWO * TWO;
}

После обработки директивы в выражении окажутся обычные двойки. TWO — не переменная: у неё нет ни объекта, ни адреса, ни значения, меняющегося во время выполнения. Это имя макроса, используемое при обработке исходного текста.

Подстановка работает с элементами текста, а не заменяет любые совпавшие подстроки: TWO внутри "TWO" останется частью строкового литерала. На курсе макросы вряд ли понадобятся, но знать, что #define и переменная — разные вещи, стоит.

Заголовки, которые встречаются сразу

ЗаголовокЧто даёт
<iostream>std::cin, std::cout, std::cerr
<iomanip>std::setw, std::setfill, std::setprecision
<cmath>std::sqrt, std::abs, std::round, std::pow
<limits>std::numeric_limits<T>::max() и min()
<cstdint>int32_t, int64_t и другие типы фиксированной ширины
<string>std::string
<vector>std::vector

Правило «подключай то, что используешь»

Каждый файл подключает заголовки для всего, что в нём упомянуто, — и не подключает лишнего. Заголовки тянут друг друга, поэтому std::sqrt может случайно оказаться доступен и без <cmath>; но это случайность конкретной реализации, и на другой платформе сборка сломается.

Обратное тоже верно: неиспользуемый #include — мусор, который замедляет компиляцию и вводит читателя в заблуждение.

Порядок и стиль

Google Style Guide задаёт порядок групп, разделённых пустой строкой: собственный заголовок этого файла, заголовки C, заголовки C++, чужие библиотеки, свои файлы проекта. Внутри группы — по алфавиту:

#include <cmath>
#include <iostream>

clang-format умеет это сортировать сам: достаточно запустить его с флагом -i, и порядок будет приведён к требуемому.

Тонкости

  • Заголовки C++ для функций из C пишутся без .h и с префиксом c: <cmath>, а не <math.h>. Тогда имена попадают в пространство std и вызываются как std::sqrt.
  • В <cmath> доступны и std::sqrt, и глобальный sqrt. Смешивать не стоит — пишите везде std::.
  • Многократное включение одного заголовка безопасно: внутри стоит защита (#pragma once или include guard). В своих заголовках её нужно ставить самому.
  • Посмотреть, во что превращается файл после препроцессора: g++ -E file.cpp | less.

Частые ошибки

  • Забыть <iomanip> и получить ошибку про setw — при том что <iostream> подключён.
  • Оставить #include <cmath> после того, как математику из кода убрали.
  • Подключить <math.h> вместо <cmath> и потерять std::.