Скільки рядків коду в наступній програмі?
#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
Зауважте, що немає #includes. Але коли ви використовуєте велику кількість зовнішніх функцій (які будуть використовувати більшість програм), їх вручну декларування стає втомливим і схильним до помилок. Набагато простіше використовувати файли заголовків.
Як сучасні мови можуть уникнути файлів заголовків?
Використовуючи інший формат файлу об'єкта, що включає інформацію про тип. Наприклад, формат файлу Java * .class включає "дескриптори", які задають типи полів та параметри методу.
Це не був новий винахід. Раніше (1987), коли Borland додав окремо складені "одиниці" до Turbo Pascal 4.0, він вирішив скористатися новим *.TPUформатом, а не Turbo C, *.OBJщоб усунути потребу у файлах заголовків.