Quante righe 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 ++ richiede così tanto tempo rispetto ad altre lingue e perché i linguaggi moderni evitano i file di intestazione.
Una domanda migliore sarebbe
Perché non C ++ ha file header?
C ++ è stato progettato per essere un superset di C, quindi ha dovuto conservare i file header per la compatibilità con le versioni precedenti.
OK, allora perché C ha i file header?
A causa del suo primitivo modello di compilazione separato. I file oggetto generati dai compilatori C non includono alcuna informazione sul tipo, 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 del tipo corretto risolve 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 (che la maggior parte dei programmi farà), dichiararle manualmente diventa noioso e soggetto a errori. È molto più facile usare i file header.
In che modo le lingue moderne sono in grado di evitare i file header?
Utilizzando un diverso formato di file oggetto che include informazioni sul tipo. Ad esempio, il formato file Java * .class include "descrittori" che specificano i tipi di campi e i parametri del metodo.
Questa non era una nuova invenzione. In precedenza (1987), quando Borland aggiunse "unità" compilate separatamente a Turbo Pascal 4.0, scelse di utilizzare un nuovo *.TPU
formato anziché Turbo C *.OBJ
per eliminare la necessità di file di intestazione.