Задать вопрос
@AslanPAPA

Заголовочные файлы в Си нужны только для интерфейса?

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

Вопрос:
Есть файлы math_functions.c и main.c. Я же могу просто в main.c использовать функции из файла math_functions.c? Но нет нужно ещё объявить этот самый math_functions.h в котором нужно определить функции, вот этого я не понимаю зачем ? Что-то там чтобы в файле main.c компилятор знал про типы функций, зачем ему знать это из заголовочного файла math_functions.h если это есть в файле math_functions.c.
Знаю ещё про то что в заголовочном файле используются #ifndef чтобы не использовать к примеру одну переменную два раз в одном файле, но это же можно и в main.c сделать.

Я сейчас понимаю что задаю глупый вопрос, который скорее всего через практику решится, но я хочу это узнать сейчас т.к начинаю делать проект с модулями и хочу правильно это сделать.
  • Вопрос задан
  • 455 просмотров
Подписаться 2 Простой 4 комментария
Помогут разобраться в теме Все курсы
  • Нетология
    Разработчик на C++
    12 месяцев
    Далее
  • Skillbox
    Профессия Разработчик С++
 с нуля + ИИ
    7 месяцев
    Далее
  • Яндекс Практикум
    Разработчик C++ расширенный
    12 месяцев
    Далее
Пригласить эксперта
Ответы на вопрос 5
wataru
@wataru Куратор тега C++
Разработчик на С++, экс-олимпиадник.
Для того, чтобы использовать в main.c функцию, определенную в math_functions.c, вам надо иметь ее объявление в main.c

Вам надо сказать компилятору, что вот такая функция есть и у нее вот такие вот параметры.

Можно просто в main.c написать то, что вы бы написали в math_functions.h. Но это быстро становится сложно, если у вас проект большой и функции используются в разных файлах. Надо будет эти объявления копировать в кучу мест. А если вам еще и поменять что-то надо потом, вы офигеете. Для этого и придумали заголовочные файлы - вы пишите объявление один раз и потом его везде используете.

Вообще, сейчас не обязательно math_functions.h включать и в math_functions.c. Раньше надо было определять функцию даже если ее объявления нигде нет. В современных стандартах это не так. Но все равно хедеры включают в соответствующий файл, чтобы ловить ошибки. Если вы поменяете функцию в .c но не поменяете в хедере, компилятор заметит несоответствие объявления и определения и сообщит об ошибке.
Ответ написан
@Mercury13
Программист на «си с крестами» и не только
Хедеры служат, чтобы два c-файла — они называются «единицы трансляции» — компилировались по отдельности. Это основное назначение той разновидности include-файлов, которые называются хедерами.

Можно в h-файлы посадить и тела функций, только убедиться, что каждое тело ровно в одной единице трансляции — есть такой подход под названием «одна единица трансляции», и он существует у больших редко перекомпилируемых библиотек, чтобы перекомпиляция была покороче.

Подключение main.c←math_functions.h служит, чтобы сказать компилятору: а где-то в другом месте есть эти функции.

Подключение math_functions.c←math_functions.h — частично для подключения прочего общего вроде типов, частично для проверки на ошибки. Дело в том, что Си традиционно не козявит (does not mangle) имена функций, и если в хедере sin(int), а в реализации sin(double) — будут трудноуловимые ошибки.

Да, деление на единицы компиляции решает и другую задачу — декомпизицию программы на меньшие элементы, и есть противоречие одного с другим (особенно в языке Си++, где хедеры огромны)

В хедере находится только то, что не производит кода. Если говорить про Си++, то…
• inline-объекты (код производят вызовы объекта)
• определения типов, функций и прочего; extern-определения переменных (код производят тела функций и окончательные определения переменных)
• шаблоны, если те нужны более чем в одной единице компиляции (код производит специализация)
Но полные специализации шаблонов производят код и находятся в cpp-файле!
Ответ написан
Комментировать
VoidVolker
@VoidVolker
Dark side eye. А у нас печеньки! А у вас?
Ну есть же всё в гугле и в манах, где очень подробно всё расписано и даже с примерами: https://ru.wikipedia.org/wiki/Заголовочный_файл
Ответ написан
CityCat4
@CityCat4 Куратор тега C
Жил да был черный кот за углом...
Ничего не мешает вообще использовать только main.c. Но по мере роста программы и ее сложности ты опухнешь каждый раз рыться в исходнике.
Ответ написан
Комментировать
@ImagineTables
Есть файлы math_functions.c и main.c. Я же могу просто в main.c использовать функции из файла math_functions.c? Но нет нужно ещё объявить этот самый math_functions.h в котором нужно определить функции, вот этого я не понимаю зачем ?


1. В отличие от других ЯП, Си плотно привязан к обработке текста. И это хорошо. Встроенный текстовой препроцессинг это его фишка, которой в других ЯП часто не хватает. Так вот, #include это не using из других языков (когда мы говорим компилятору, что хотим пользоваться таким-то модулем). Это копирование сырого текста из файла в заданное место.

2. Каждый файл .c/.cpp компилируется по отдельности. И компилятор работает с текстом этого файла, а не рассматривает его как модуль какого-то проекта. Если в main.c написать вызов функции из math_functions.c, компилятор эту функцию тупо не найдёт (её же в main.c нет). Значит, компилятору надо сказать перед вызовом каждой функции, что ГДЕ-ТО есть функция с такой сигнатурой (с таким именем и параметрами). Для этого перед первым вызовом функции должно идти её объявление без реализации, заканчивающееся вместо тела символом ;. Раз перед первым вызовом — самое удобное место это начало файла.

3. Чтобы не копипастить эти объявления без реализации руками, их выносят в файл math_functions.h, который при помощи #include подставляется в начало КАЖДОГО файла, где планируется их использовать, и таким образом эти объявления появляются в каждом файле .c/.cpp в виде текста.

4. При линковке проекта (когда откомпилированные по отдельности объектные файлы собираются в единый бинарник) линкер привязывает все вызовы мат.функций из main.c к их реализации из math_functions.c, используя имена как идентификаторы.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы