В составлении нет ничего волшебного. Ни автоматический!
Заголовочные файлы в основном предоставляют информацию компилятору, почти никогда не кодируют.
Одной этой информации обычно недостаточно для создания полной программы.
Рассмотрим программу «hello world» (с более простой функцией puts
):
#include <stdio.h>
int main(void) {
puts("Hello, World!");
return 0;
}
без заголовка компилятор не знает, как обращаться с puts()
(это не ключевое слово C). Заголовок позволяет компилятору знать, как управлять аргументами и возвращаемым значением.
Однако, как эта функция работает, нигде в этом простом коде не указано. Кто-то еще написал код для puts()
и включил скомпилированный код в библиотеку. Код в этой библиотеке включен в скомпилированный код для вашего источника как часть процесса компиляции.
Теперь рассмотрим, что вы хотели свою собственную версию puts()
int main(void) {
myputs("Hello, World!");
return 0;
}
Компиляция только этого кода дает ошибку, потому что у компилятора нет информации о функции. Вы можете предоставить эту информацию
int myputs(const char *line);
int main(void) {
myputs("Hello, World!");
return 0;
}
и код теперь компилируется --- но не связывается, т.е. не создает исполняемый файл, потому что нет кода для myputs()
. Таким образом, вы пишете код для myputs()
в файле с именем "myputs.c"
#include <stdio.h>
int myputs(const char *line) {
while (*line) putchar(*line++);
return 0;
}
и вы должны не забыть скомпилировать и ваш первый исходный файл и "myputs.c" вместе.
Через некоторое время ваш файл "myputs.c" расширился до набора функций, и вам необходимо включить информацию обо всех функциях (их прототипах) в исходные файлы, которые хотят их использовать.
Удобнее записать все прототипы в один файл и #include
этот файл. С включением вы не рискуете ошибиться при наборе прототипа.
Вам все равно придется скомпилировать и связать все файлы кода вместе.
Когда они растут еще больше, вы помещаете весь уже скомпилированный код в библиотеку ... и это другая история:)