Quantas linhas de código estão no programa a seguir?
#include <iostream>
int main()
{
std::cout << "Hello, world!\n";
return 0;
}
Você provavelmente respondeu 7 (ou 6, se não contou a linha em branco, ou 4, se não contou as chaves).
Seu compilador, no entanto, vê algo muito diferente:
~$ cpp hello.cpp | wc
18736 40822 437015
Sim, são 18,7 KLOC apenas para um "Olá, mundo!" programa. O compilador C ++ precisa analisar tudo isso. Esse é um dos principais motivos pelos quais a compilação do C ++ demora tanto tempo em comparação com outras linguagens, e porque as linguagens modernas evitam os arquivos de cabeçalho.
Uma pergunta melhor seria
Por que o C ++ possui arquivos de cabeçalho?
O C ++ foi projetado para ser um superconjunto de C, portanto, era necessário manter os arquivos de cabeçalho para compatibilidade com versões anteriores.
OK, então por que C tem arquivos de cabeçalho?
Por causa de seu modelo de compilação primitivo separado. Os arquivos de objeto gerados pelos compiladores C não incluem nenhuma informação de tipo, portanto, para evitar erros de tipo, você precisa incluir essas informações em seu código-fonte.
~$ 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
Adicionar as declarações de tipo adequadas corrige o erro:
~$ 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
Observe que não há #include
s. Mas quando você usa um grande número de funções externas (o que a maioria dos programas fará), declará-las manualmente fica entediante e propenso a erros. É muito mais fácil usar arquivos de cabeçalho.
Como as linguagens modernas são capazes de evitar arquivos de cabeçalho?
Usando um formato de arquivo de objeto diferente que inclui informações de tipo. Por exemplo, o formato de arquivo Java * .class inclui "descritores" que especificam os tipos de campos e parâmetros de método.
Esta não era uma nova invenção. Antes (1987), quando a Borland adicionou "unidades" compiladas separadamente ao Turbo Pascal 4.0, optou por usar um novo *.TPU
formato em vez do Turbo C, a *.OBJ
fim de remover a necessidade de arquivos de cabeçalho.