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