Сколько строк кода в следующей программе?
#include <iostream>
int main()
{
std::cout << "Hello, world!\n";
return 0;
}
Вы, вероятно, ответили 7 (или 6, если вы не считали пустую строку, или 4, если вы не считали скобки).
Ваш компилятор, однако, видит что-то совсем другое:
~$ cpp hello.cpp | wc
18736 40822 437015
Да, это 18,7 KLOC только для "Привет, мир!" программа. Компилятор C ++ должен проанализировать все это. Это главная причина, почему компиляция C ++ занимает так много времени по сравнению с другими языками, и почему современные языки избегают заголовочных файлов.
Лучший вопрос будет
Почему же C ++ есть файлы заголовков?
C ++ был разработан, чтобы быть надмножеством C, поэтому он должен был хранить заголовочные файлы для обратной совместимости.
Хорошо, так почему C имеет заголовочные файлы?
Из-за своей примитивной отдельной модели компиляции. Объектные файлы, сгенерированные компиляторами C, не содержат никакой информации о типе, поэтому для предотвращения ошибок типа вам необходимо включить эту информацию в ваш исходный код.
~$ cat sqrtdemo.c
int main(void)
{
/* implicit declaration int sqrt(int) */
double sqrt2 = sqrt(2);
printf("%f\n", sqrt2);
return 0;
}
~$ gcc -Wall -ansi -lm -Dsqrt= sqrtdemo.c
sqrtdemo.c: In function ‘main’:
sqrtdemo.c:5:5: warning: implicit declaration of function ‘printf’ [-Wimplicit-function-declaration]
sqrtdemo.c:5:5: warning: incompatible implicit declaration of built-in function ‘printf’ [enabled by default]
~$ ./a.out
2.000000
Добавление правильных объявлений типов исправляет ошибку:
~$ cat sqrtdemo.c
#undef printf
#undef sqrt
int printf(const char*, ...);
double sqrt(double);
int main(void)
{
double sqrt2 = sqrt(2);
printf("%f\n", sqrt2);
return 0;
}
~$ gcc -Wall -ansi -lm sqrtdemo.c
~$ ./a.out
1.414214
Обратите внимание, что нет #include
s. Но когда вы используете большое количество внешних функций (что делает большинство программ), их ручное объявление становится утомительным и подверженным ошибкам. Гораздо проще использовать заголовочные файлы.
Как современные языки могут избежать заголовочных файлов?
Используя другой формат объектного файла, который включает информацию о типе. Например, формат файла Java * .class включает «дескрипторы», которые определяют типы полей и параметры метода.
Это не было новым изобретением. Ранее (1987), когда Borland добавил отдельно скомпилированные «модули» в Turbo Pascal 4.0, он решил использовать новый *.TPU
формат, а не Turbo C, *.OBJ
чтобы устранить необходимость в заголовочных файлах.