Любое фундаментальное различие между исходными и заголовочными файлами в C?
Я не совсем понимаю, как вещи должны быть разделены в исходных и заголовочных файлах C. Я часто вижу много проектов с двумя наборами файлов с тем же именем (без расширения, обозначающего исходные и заголовочные файлы).
До сих пор, из-за этого непонимания, когда я писал библиотеки, я вложил весь код класса и класса в один файл с нерешительностью в отношении выбора расширения файла.
Что должно быть в заголовках и что должно быть в исходных файлах? Как реализовать это разделение?
Ответы
Ответ 1
Нет технической разницы. Компилятор с радостью позволит вам добавить файл .c
или скомпилировать файл .h
, если хотите.
Существует, однако, огромное культурное различие:
-
Объявления (прототипы) входят в файлы .h
. Файл .h
является интерфейсом к тому, что реализовано в соответствующем файле .c
.
-
Определения входят в файлы .c
. Они реализуют интерфейс, указанный в файле .h
.
Разница в том, что файл .h
может (и обычно будет) #include
d на несколько единиц компиляции (.c
files). Если вы определите функцию в файле .h
, она окажется в нескольких файлах .o
, и компоновщик будет жаловаться на многократно определенный символ. Вот почему определения не должны входить в файлы .h
. (Исключением являются встроенные функции.)
Если функция определена в файле .c
и вы хотите использовать ее из других файлов .c
, объявление этой функции должно быть доступно в каждом из этих других файлов .c
. Вот почему вы помещаете объявление в .h
и #include
, что в каждом из них. Вы также можете повторить объявление в каждом файле .c
, но это приводит к большому количеству дублирования кода и неуправляемому беспорядку.
Если функция определена в файле .c
, но вы не хотите использовать ее из других файлов .c
, нет необходимости объявлять ее в заголовке. Это, по сути, деталь реализации этого файла .c
. В этом случае также создайте функцию static
, поэтому она не конфликтует с идентично именованными функциями в других файлах.
Ответ 2
Что должно быть в заголовках и что должно быть в исходных файлах?
Обычно заголовки содержат одно или несколько из следующих элементов:
- Объявление функции (кроме статики)
- Объявление переменной (обычно глобальное)
- Объявление пользовательского типа (читайте
struct
, union
и т.д.)
- Определение макроса
С другой стороны, исходные файлы имеют:
- Определение функции/переменной
- Объявление и определение статической функции (вы не хотите раскрывать их своим клиентам)
- Переменное определение
- Некоторые предпочитают определять встроенные функции (C99) в заголовке
Как реализовать это разделение?
Правило одного определения - ваш друг.
Помните, что если вы пишете библиотеку, это то, что видит ваш клиент. Итак, будьте полезны и предоставите всю информацию, которую вы можете использовать, чтобы использовать вашу библиотеку. Исходные файлы обычно компилируются и передаются в двоичной форме.
И, кстати, у C нет понятия классов.
Ответ 3
Обычно заголовочные файлы содержат декларации, исходные файлы содержат код.
Итак, если в исходном файле A.c
вам нужна функция, реализованная в исходном файле B.c
, вы просто включаете B.h
для ее объявления.
Ответ 4
Существует незначительная принципиальная разница между .c и .h файлами (хотя некоторые компиляторы могут отказаться от компиляции файла .h). Разница более согласуется.
Обычно файл .h предоставляет API, а .c обеспечивает реализацию.
Поэтому файл .h будет содержать только вещи, необходимые для других исходных файлов, для доступа к средствам, предоставленным вашим .c файлом. Таким образом, файлы .h будут предоставлять прототипы функций глобальных функций, декларации глобальных переменных (если они действительно нужны), а также структуры и другие типы, используемые ими. (Не выставляйте структуру, если API-интерфейс требуется только указателю на структуру.)
Встроенные функции также часто включаются в файлы .h, но некоторые рекомендации по кодированию предпочитают использовать отдельное расширение (например,.inl)
Все другие реализации функций, определение и инициализация переменных и декларации локальных (статических) переменных и функций будут в файле .c.