.h или .hpp для заголовочных файлов C++? Разбираем раз и навсегда

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

.h или .hpp для заголовочных файлов C++? Разбираем раз и навсегда

Если вы когда-нибудь писали на C++ больше пары недель, то наверняка сталкивались с этим вопросом. Открываете чужой проект — там .h. Свой начинаете — в голове голос: «А может, .hpp круче?». Или наоборот: вы ярый фанат .h, а коллега утверждает, что .hpp — это единственно верный путь.

Спойлер: оба варианта технически корректны. Компилятору всё равно. Но разница есть, и она важна для организации кода, читаемости и поддержки проекта. Давайте разберёмся, что стоит за этими двумя расширениями, и когда какое выбирать.

Короткий ответ: в чём принципиальная разница?

Если совсем кратко:

  • .h — традиционное расширение для заголовочных файлов, пришедшее из C. Используется и в C, и в C++.
  • .hpp — более современное расширение, которое явно указывает: «Это C++, а не C». Придумано, чтобы отличать C++ заголовки от C-шных.

Но дьявол, как всегда, в деталях. Давайте копнём глубже.

Исторический контекст: откуда взялись .h и .hpp?

Язык C использовал .h для заголовков с незапамятных времён. Когда появился C++, первое время программисты просто продолжали использовать .h — и это нормально. Стандартная библиотека C++ (например, <iostream>) вообще отказалась от расширений, но это уже другая история.

Расширение .hpp появилось как ответ на потребность разделять C и C++ код. Представьте: у вас большой проект, где часть файлов на C, часть на C++. Собираете вы его, возможно, разными компиляторами или с разными флагами. Как быстро понять, какой заголовок для какого языка? Правильно — посмотреть на расширение.

Так .hpp (от «C Plus Plus header») стал де-факто стандартом в сообществе для чистых C++ заголовков, особенно в библиотеках вроде Boost.

Когда использовать .h?

Не спешите хоронить .h. У него есть свои сильные стороны:

  • Совместимость с C. Если ваш заголовочный файл должен подключаться и из C, и из C++ кода — только .h. Никаких вариантов.
  • Консервативные проекты. В крупных кодовых базах, где стиль сложился годами, менять расширения на .hpp — лишняя боль.
  • Минимализм. Три символа вместо четырёх. Мелочь, а приятно.

Пример: заголовок, совместимый с C и C++

// math_utils.h
#ifndef MATH_UTILS_H
#define MATH_UTILS_H

#ifdef __cplusplus
extern "C" {
#endif

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

#ifdef __cplusplus
}
#endif

#endif // MATH_UTILS_H

Такой файл можно подключить и в .c, и в .cpp. Если бы вы назвали его math_utils.hpp, программист на C мог бы запутаться: «А это точно для меня?».

Когда использовать .hpp?

Здесь всё наоборот: .hpp — выбор современного C++ программиста. Особенно если:

  • Вы пишете только на C++. Никакого C в проекте нет и не будет.
  • Используете шаблоны, STL, исключения. Это чисто C++-ные фишки, и расширение .hpp подчёркивает это.
  • Хотите явно отделить C++ код от C. В смешанных проектах это спасает от путаницы.
  • Следуете современным практикам. Boost, Qt (частично), многие новые библиотеки используют .hpp.

Пример: типичный C++ заголовок с классом

// player.hpp
#ifndef PLAYER_HPP
#define PLAYER_HPP

#include <string>
#include <vector>

class Player {
public:
    Player(const std::string& name, int health);
    
    void takeDamage(int amount);
    void heal(int amount);
    bool isAlive() const;
    
    const std::string& getName() const { return name_; }

private:
    std::string name_;
    int health_;
    std::vector<std::string> inventory_;
};

#endif // PLAYER_HPP

Видите? Здесь нет extern "C", нет C-совместимых структур. Это чистый C++. Расширение .hpp сразу даёт понять: «Не пытайся подключить меня из C, я сломаюсь».

А что насчёт других расширений? .hxx, .hh, .H?

О, мир C++ многообразен. Встречаются и такие варианты:

  • .hxx — альтернатива .hpp, популярна в некоторых сообществах (например, в проектах, использующих CMake).
  • .hh — редко, но метко. Иногда используется как аналог .hpp.
  • .H — на системах, где регистр важен (например, в некоторых Unix-инструментах). Лучше избегать — путаница с файлами Fortran.

На практике 99% проектов используют либо .h, либо .hpp. Остальные — экзотика для гиков.

Что говорит стандарт C++?

А ничего. Стандарт C++ не регламентирует расширения заголовочных файлов. Вообще. Ему всё равно, назовёте вы файл foo.h, foo.hpp или foo.unicorn. Директива #include работает с любым текстовым файлом.

Так что технически вы вольны выбирать любое расширение. Но сообщество выработало негласные правила, и их стоит уважать.

Практические рекомендации: как выбрать?

Вот простой чек-лист, который поможет принять решение:

Ситуация Рекомендуемое расширение
Заголовок используется и в C,

Блоги

Рекомендаций по книгам