C/C++ включает порядок заголовочного файла

Какой порядок должен включать файлы быть указанным, т.е. каковы причины включения одного заголовка перед другим?

Например, системные файлы, STL и Повышение идут, прежде или после того, как локальные включают файлы?

264
задан Peter Tseng 23 October 2018 в 14:36
поделиться

8 ответов

Я не думаю, что есть рекомендуемый порядок, если он компилируется! Что раздражает, так это то, что некоторые заголовки требуют, чтобы сначала были включены другие заголовки ...Это проблема самих заголовков, а не порядка включения.

Лично я предпочитаю перейти от локального к глобальному, каждый подраздел в алфавитном порядке, то есть:

  1. h файл, соответствующий этому cpp-файлу (если применимо)
  2. заголовки из того же компонента,
  3. заголовки из другие компоненты,
  4. системные заголовки.

Мое обоснование для 1. состоит в том, что он должен доказать, что каждый заголовок (для которого есть cpp) может быть #include d без предварительных условий. А остальное, кажется, логически вытекает отсюда.

265
ответ дан 23 November 2019 в 02:29
поделиться

Это не субъективно. Убедитесь, что ваши заголовки не полагаются на #include d в определенном порядке. Вы можете быть уверены, что не имеет значения, в каком порядке вы включаете заголовки STL или Boost.

6
ответ дан 23 November 2019 в 02:29
поделиться

Сначала включите заголовок, соответствующий .cpp ... другими словами, source1.cpp должен включать source1. h перед включением чего-либо еще. Единственное исключение, о котором я могу думать, - это использование MSVC с предварительно скомпилированными заголовками, и в этом случае вы вынуждены включать stdafx.h прежде всего.

Обоснование: Включение source1.h перед любыми другими файлами гарантирует, что он может работать автономно без зависимостей. Если source1.h принимает зависимость от более поздней даты, компилятор немедленно предупредит вас, чтобы вы добавили необходимые форвардные объявления в source1.h . Это, в свою очередь, гарантирует, что заголовки могут быть включены в любом порядке их иждивенцами.

Пример:

source1.h

class Class1 {
    Class2 c2;    // a dependency which has not been forward declared
};

source1.cpp

#include "source1.h"    // now compiler will alert you saying that Class2 is undefined
                    // so you can forward declare Class2 within source1.h
...

Пользователи MSVC: Я настоятельно рекомендую использовать предварительно скомпилированные заголовки. Итак, переместите все директивы #include для стандартных заголовков (и других заголовков, которые никогда не изменятся) в stdafx.h .

3
ответ дан 23 November 2019 в 02:29
поделиться

Чтобы добавить свой кирпич к стене.

  1. Каждый заголовок должен быть самодостаточным, что может быть протестировано только в том случае, если он включен вначале хотя бы один раз
  2. Не следует ошибочно изменять значение стороннего заголовка, вводя символы (макрос, типы и т. Д.) )

Обычно я говорю так:

// myproject/src/example.cpp
#include "myproject/example.h"

#include <algorithm>
#include <set>
#include <vector>

#include <3rdparty/foo.h>
#include <3rdparty/bar.h>

#include "myproject/another.h"
#include "myproject/specific/bla.h"

#include "detail/impl.h"

Каждая группа отделяется пустой строкой от следующей:

  • Сначала заголовок, соответствующий этому файлу cpp (проверка работоспособности)
  • Системные заголовки
  • Третий- партийные заголовки, организованные по порядку зависимости
  • Заголовки проекта
  • Частные заголовки проекта

Также обратите внимание, что, помимо системных заголовков, каждый файл находится в папке с именем своего пространства имен просто потому, что их легче отслеживать вниз по этой дороге.

21
ответ дан 23 November 2019 в 02:29
поделиться

Включайте от наиболее специфичного к наименее специфичному, начиная с соответствующего .hpp для .cpp, если такой существует. Таким образом, будут выявлены любые скрытые зависимости в заголовочных файлах, которые не являются самодостаточными.

Это осложняется использованием предварительно скомпилированных заголовков. Один из способов обойти это, не делая свой проект специфичным для компилятора, - использовать один из заголовков проекта в качестве включаемого файла предварительно скомпилированного заголовка.

2
ответ дан 23 November 2019 в 02:29
поделиться

Я уверен, что это не является рекомендуемой практикой в здравом мире, но мне нравится выстраивать системные include по длине имени файла, сортируя их лексически в пределах одной длины. Например:

#include <set>
#include <vector>
#include <algorithm>
#include <functional>

Я думаю, что это хорошая идея - включать свои собственные заголовки перед чужими, чтобы избежать позора зависимости порядка включения.

14
ответ дан 23 November 2019 в 02:29
поделиться

Я следую двум простым правилам, которые избегают подавляющего большинства проблем:

  1. Все заголовки (и действительно любые исходные файлы) должны включать то, что им нужно. Они должны не полагаться на своих пользователей, включая вещи.
  2. В качестве дополнения все заголовки должны включать в себя ограждения, чтобы они не включались несколько раз из-за чрезмерно амбициозного применения правила 1 выше.

Я также следую рекомендациям:

  1. Сначала включите системные заголовки (stdio.h и т. д.) с разделительной линией.
  2. Сгруппируйте их логически.

Другими словами:

#include <stdio.h>
#include <string.h>

#include "btree.h"
#include "collect_hash.h"
#include "collect_arraylist.h"
#include "globals.h"

Хотя, будучи руководящими принципами, это субъективная вещь. Правила, с другой стороны, я применяю жестко, вплоть до предоставления «оберточных» заголовочных файлов с включенными защитами и сгруппированных включений, если какой-то неприятный сторонний разработчик не подписывается под моим видением :-)

48
ответ дан 23 November 2019 в 02:29
поделиться

Я рекомендую:

  1. Заголовок для модуля .cc, который вы создаете. (Помогает убедиться, что каждый заголовок в проекте не имеет неявных зависимостей от других заголовков в проекте.)
  2. Системные файлы C.
  3. Системные файлы C++.
  4. Платформа / ОС / другие заголовочные файлы (например, win32, gtk, openGL).
  5. Другие файлы заголовков из проекта.

И, конечно же, алфавитный порядок внутри каждого раздела, где это возможно.

Всегда используйте объявления пересылки, чтобы избежать ненужных #include в заголовочных файлах.

14
ответ дан 23 November 2019 в 02:29
поделиться