Должен ли я помещать их в заголовочный файл или исходный файл? Если заголовочный файл содержит инструкции include, то если я включу этот заголовочный файл в свой исходный код, то будет ли в моем исходном файле все входящие в него файлы, которые были в моем заголовке? Или я должен просто включать их только в исходный файл?
Куда поставить включенные утверждения, заголовок или источник?
Ответ 1
Только put включает в заголовок, если сам заголовок нуждается в них.
Примеры:
- Функция возвращает тип
size_t
. Затем#include <stddef.h>
в файле заголовка. - В вашей функции используется
strlen
. Затем#include <string.h>
в исходном файле.
Ответ 2
За эти годы было довольно много разногласий. В свое время было традиционным, что заголовок объявляет только то, что было в каком-либо модуле, к которому он был связан, поэтому у многих заголовков были особые требования к тому, что вы #include
определенный набор заголовков (в определенном порядке). Некоторые чрезвычайно традиционные программисты C все еще следуют этой модели (религиозно, по крайней мере в некоторых случаях).
Совсем недавно появилось движение к тому, чтобы сделать большинство заголовков автономными. Если этот заголовок требует чего-то другого, сам заголовок обрабатывает это, гарантируя, что все, что ему нужно, включено (в правильном порядке, если есть проблемы с упорядочением). Лично я предпочитаю это - особенно когда порядок заголовков может быть важен, он решает проблему один раз, вместо того, чтобы требовать от всех, кто его использует, снова решить проблему.
Обратите внимание, что большинство заголовков должны содержать только объявления. Это означает, что добавление ненужного заголовка не должно (обычно) оказывать какое-либо влияние на ваш окончательный исполняемый файл. Хуже всего то, что он немного замедляет компиляцию.
Ответ 3
Ваш #include
должен состоять из файлов заголовков, и каждый файл (источник или заголовок) должен #include
файлы заголовков, в которых он нуждается. Заголовочные файлы должны #include
использовать минимальные файлы заголовков, а также исходные файлы, хотя это не так важно для исходных файлов.
Исходный файл будет иметь заголовки #include
s, а заголовки - #include
и т.д. до максимальной глубины вложенности. Вот почему вы не хотите лишних #include
в заголовочных файлах: они могут привести к тому, что исходный файл будет содержать много файлов заголовков, которые ему могут не понадобиться, замедляя компиляцию.
Это означает, что вполне возможно, что заголовочные файлы могут быть включены дважды, и это может быть проблемой. Традиционный метод заключается в том, чтобы включить "включить охранников" в файлы заголовков, например, для файла foo.h:
#ifndef INCLUDE_FOO_H
#define INCLUDE_FOO_H
/* everything in header goes here */
#endif
Ответ 4
Если заголовочный файл A #includes
заголовочные файлы B и C, то каждый исходный файл, который #includes
A также получит B и C #included
. Препроцессор буквально просто выполняет замену текста: везде, где он находит текст, который говорит #include <foo.h>
, он заменяет его текстом файла foo.h
.
Существуют разные мнения о том, следует ли помещать #includes
в заголовки или исходные файлы. Лично я предпочитаю поместить все #includes
в исходный файл по умолчанию, но любые файлы заголовков, которые невозможно скомпилировать без других предварительных заголовков, должны #include
сами эти заголовки.
И каждый заголовочный файл должен содержать включенный защитник, чтобы предотвратить его включение несколько раз.
Ответ 5
Сделайте все свои файлы так, чтобы они могли быть построены с использованием только того, что они включают. Если вам не нужно включать в свой заголовок, удалите его. В большом проекте, если вы не поддерживаете эту дисциплину, вы оставляете себя открытым для взлома всей сборки, когда кто-то удаляет включение из файла заголовка, который используется потребителем этого файла, а не даже заголовком.
Ответ 6
В некоторых средах компиляция будет самой быстрой, если в нее будут включены только файлы заголовков. В других средах компиляция будет оптимизирована, если все исходные файлы могут использовать одну и ту же основную коллекцию заголовков (некоторые файлы могут иметь дополнительные заголовки за пределами общего подмножества). В идеале, заголовки должны быть построены так, что несколько операций #include не будут иметь никакого эффекта. Может быть полезно окружать #include заявлениями с проверкой включенного файла include-guard, хотя это создает зависимость от формата этого защитника. Кроме того, в зависимости от поведения кэширования системного файла ненужный #include, чья цель заканчивается полностью # ifdef'ed away, может не занять много времени.
Еще одна вещь, которую следует учитывать, состоит в том, что если функция принимает указатель на структуру, можно записать прототип как
void foo(struct BAR_s *bar);
без определения для BAR_s, которые должны быть в области видимости. Очень удобный подход для предотвращения ненужных включений.
PS - во многих моих проектах будет файл, который ожидал, что каждый модуль будет #include, содержащий такие вещи, как typedefs для целых размеров и несколько общих структур и объединений [например,
typedef union { unsigned long l; unsigned short lw[2]; unsigned char lb[4]; } U_QUAD;
(Да, я знаю, что у меня были бы проблемы, если бы я перешел к архитектуре большого конца, но поскольку мой компилятор не разрешает анонимные структуры в союзах, использование именованных идентификаторов для байтов в союзе потребует, чтобы они доступ к ним как theUnion.b.b1 и т.д., что кажется довольно раздражающим.
Ответ 7
Подход, который я разработал более двадцати лет, заключается в следующем:
Рассмотрим библиотеку.
Существует несколько файлов C, один внутренний H файл и один внешний H файл. Файлы C включают внутренний файл H. Внутренний файл H содержит внешний файл H.
Вы видите, что из компиляторов POV, когда он компилирует файл C, существует иерархия;
внешний → внутренний → код C
Это правильный порядок, так как внешний - это все, что третья сторона должна использовать в библиотеке. Для компиляции кода C требуется то, что является внутренним.
Ответ 8
В исходный файл будут включены инструкции include, если вы поместите его в заголовок. Однако в некоторых случаях было бы лучше поместить их в исходный файл.
Помните, что если вы включите этот заголовок в какие-либо другие источники, они также получат включения из заголовка, и это не всегда желательно. Вы должны включать только материал, в котором он используется.
Ответ 9
Вы должны включать только файлы в своем заголовке, которые нужно объявлять константами и объявлениями функций. Технически, они также будут включены в ваш исходный файл, но для большей ясности вы должны включать только в каждый файл файлы, которые вам действительно нужны. Вы также должны защитить их в своем заголовке от множественного включения:
#ifndef NAME_OF_HEADER_H
#define NAME_OF_HEADER_H
...definition of header file...
#endif
Это предотвращает включение заголовка несколько раз, что приводит к ошибке компилятора.