Quante linee di codice ci sono nel seguente programma?
#include <iostream>
int main()
{
std::cout << "Hello, world!\n";
return 0;
}
Probabilmente hai risposto 7 (o 6 se non hai contato la riga vuota, o 4 se non hai contato le parentesi graffe).
Il tuo compilatore, tuttavia, vede qualcosa di molto diverso:
~$ cpp hello.cpp | wc
18736 40822 437015
Sì, questo è 18,7 KLOC solo per un "Ciao, mondo!" programma. Il compilatore C ++ deve analizzare tutto ciò. Questo è uno dei motivi principali per cui la compilazione C ++ impiega così tanto tempo rispetto ad altri lingue e il motivo per cui le lingue moderne scansano i file di intestazione.
Una domanda migliore sarebbe
Perché C + + ha file di intestazione?
C ++ è stato progettato per essere un superset di C, quindi ha dovuto mantenere i file di intestazione per la compatibilità all'indietro.
OK, quindi perché C ha i file header?
A causa del suo primitivo modello di compilazione separato. I file oggetto generati dai compilatori C non includono informazioni sui tipi, quindi per evitare errori di tipo è necessario includere queste informazioni nel codice sorgente.
~$ 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
L'aggiunta delle dichiarazioni di tipo corrette corregge il bug:
~$ 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
Si noti che non ci sono #include
s. Ma quando si utilizza un gran numero di funzioni esterne (la maggior parte dei programmi lo farà), dichiararle manualmente diventa noioso e soggetto a errori. È molto più semplice utilizzare i file di intestazione.
In che modo le lingue moderne sono in grado di evitare i file di intestazione?
Usando un diverso formato di file oggetto che include informazioni sul tipo. Ad esempio, il formato di file * .class Java include " descrittori "che specificano i tipi di campi e i parametri del metodo.
Questa non era una nuova invenzione. In precedenza (1987), quando Borland ha aggiunto "unità" compilate separatamente a Turbo Pascal 4.0, ha scelto di utilizzare un nuovo formato *.TPU
anziché il *.OBJ
di Turbo C per rimuovere la necessità di file di intestazione.