Должен ли я помещать включения в файл заголовка или исходный файл? Если файл заголовка содержит операторы include, то если я включу этот файл заголовка в свой источник, тогда будет ли в моем исходном файле все включенные файлы, которые были в моем заголовке? Или я должен просто включить их только в исходный файл?
107
Ответы:
Включайте в заголовок только в том случае, если они нужны самому заголовку.
Примеры:
size_t
. Затем#include <stddef.h>
в заголовочном файле.strlen
. Затем#include <string.h>
в исходном файле.источник
size_t
?size_t
илиstd::string
?На протяжении многих лет по этому поводу было довольно много разногласий. Когда-то было традиционным, что заголовок объявлял только то, что было в каком-либо модуле, к которому он был связан, поэтому многие заголовки имели определенные требования, что вам
#include
нужен определенный набор заголовков (в определенном порядке). Некоторые чрезвычайно традиционные программисты на C все еще следуют этой модели (по крайней мере, в некоторых случаях религиозно).В последнее время наблюдается движение к тому, чтобы сделать большинство заголовков автономными. Если для этого заголовка требуется что-то еще, сам заголовок обрабатывает это, обеспечивая включение всего, что ему нужно (в правильном порядке, если есть проблемы с порядком). Лично я предпочитаю это - особенно когда порядок заголовков может быть важен, он решает проблему один раз, вместо того, чтобы требовать от всех, кто его использует, снова решать проблему.
Обратите внимание, что большинство заголовков должны содержать только объявления. Это означает, что добавление ненужного заголовка (обычно) не должно иметь никакого влияния на ваш окончательный исполняемый файл. Худшее, что случается, - это немного замедляет компиляцию.
источник
Ваш
#include
s должен быть из файлов заголовков, и каждый файл (исходный или заголовочный) должен содержать файлы#include
заголовков, которые ему нужны. Заголовочные файлы должны иметь#include
необходимый минимум заголовочных файлов, и исходные файлы также должны, хотя это не так важно для исходных файлов.Исходный файл будет иметь заголовки
#include
, а также их заголовки#include
и так далее до максимальной глубины вложения. Вот почему вам не нужны лишние#include
s в файлах заголовков: они могут привести к тому, что исходный файл будет включать множество файлов заголовков, которые могут не понадобиться, замедляя компиляцию.Это означает, что вполне возможно, что файлы заголовков могут быть включены дважды, и это может быть проблемой. Традиционный метод состоит в том, чтобы добавить "охранников включения" в файлы заголовков, например, для файла foo.h:
источник
Подход, который я выработал более двадцати лет, таков;
Рассмотрим библиотеку.
Есть несколько файлов C, один внутренний H-файл и один внешний H-файл. Файлы C включают внутренний файл H. Внутренний файл H включает внешний файл H.
Вы видите, что из POV компилятора, когда он компилирует файл C, существует иерархия;
внешний -> внутренний -> код C
Это правильный порядок, поскольку внешнее - это все, что нужно третьей стороне для использования библиотеки. То, что является внутренним, требуется для компиляции кода C.
источник
Если файл заголовка
#includes
файлы заголовков В и С, то каждый исходный файл ,#includes
А будет также получить B и C#included
. Препроцессор буквально выполняет замену текста: везде, где он находит текст, говорится, что#include <foo.h>
он заменяет его текстомfoo.h
файла.Существуют разные мнения о том, следует ли вставлять
#includes
заголовочные файлы или исходные файлы. Лично я предпочитаю помещать все#includes
в исходный файл по умолчанию, но любые файлы заголовков, которые не могут быть скомпилированы без других предварительных заголовков, должны использовать#include
сами заголовки.И каждый файл заголовка должен содержать защиту включения, чтобы предотвратить его многократное включение.
источник
Сделайте все свои файлы так, чтобы они могли быть построены с использованием только того, что они включают. Если вам не нужно включать в заголовок, удалите его. В большом проекте, если вы не поддерживаете эту дисциплину, вы оставляете себя открытым для нарушения всей сборки, когда кто-то удаляет включение из файла заголовка, который используется потребителем этого файла, а не даже заголовком.
источник
В некоторых средах компиляция будет самой быстрой, если в нее будут включены только нужные файлы заголовков. В других средах компиляция будет оптимизирована, если все исходные файлы могут использовать одну и ту же основную коллекцию заголовков (некоторые файлы могут иметь дополнительные заголовки помимо общего подмножества). В идеале заголовки должны быть созданы так, чтобы несколько операций #include не имели никакого эффекта. Было бы неплохо окружить операторы #include проверками include-guard для включаемого файла, хотя это создает зависимость от формата этого средства защиты. Кроме того, в зависимости от поведения кэширования файлов в системе, необязательный #include, цель которого оказывается полностью удаленным # ifdef, может не занять много времени.
Также следует учитывать, что если функция принимает указатель на структуру, можно записать прототип как
без определения того, что BAR_s должны быть в области видимости. Очень удобный подход, позволяющий избежать ненужных включений.
PS - во многих моих проектах будет файл, который, как ожидается, каждый модуль будет #include, содержащий такие вещи, как typedef для целочисленных размеров и несколько общих структур и объединений [например,
(Да, я знаю, что у меня будут проблемы, если я перейду на архитектуру с прямым порядком байтов, но поскольку мой компилятор не разрешает анонимные структуры в объединениях, использование именованных идентификаторов для байтов в объединении потребует доступа к ним как theUnion.b.b1 и т.д., что кажется довольно раздражающим.
источник
Ваш исходный файл будет содержать операторы include, если вы поместите его в заголовок. Однако в некоторых случаях было бы лучше поместить их в исходный файл.
Помните, что если вы включите этот заголовок в любые другие источники, они также получат включение из заголовка, а это не всегда желательно. Вы должны включать только то, что используется.
источник
Вы должны включать в свой заголовок только те файлы, которые необходимы для объявления констант и функций. Технически, эти включения также будут включены в ваш исходный файл, но для ясности вы должны включать в каждый файл только те файлы, которые вам действительно нужны. Вы также должны защитить их в своем заголовке от множественного включения следующим образом:
Это предотвращает включение заголовка несколько раз, что приведет к ошибке компилятора.
источник