paulo1205
(usa Ubuntu)
Enviado em 19/10/2017 - 17:37h
Não é só velocidade.
Imagine o programa como o Linux ou o Windows, ambos escritos em C.
Que tamanho você acha que esses programas têm? O kernel Linux tem 15 milhões de linhas. Alega-se que o Windows tem na casa de 50 milhões.
E quantas pessoas trabalham ao mesmo tempo em cada um deles? Não menos do que alguns milhares de programadores.
É teoricamente possível colocar todo o Linux ou todo o Windows num arquivo só, mas você acha que é uma boa ideia?
O C (e várias outras linguagens, na verdade) permite (mas não exige) uma forma de se trabalhar com a compilação em separado de várias partes do programa, que são posteriormente unidas pelo
linker. Dividir o programa em partes facilita o trabalho em equipe, com cada membro bloqueando apenas a parte em que está trabalhando, não o programa todo. Além disso, quando se faz uma modificação em uma das partes, só é necessário recompilar os arquivos alterados, não todos os arquivos que compõem o programa (se eles já estiverem compilados, obviamente).
Mas resta um problema: com o programa dividido, como é que uma parte sabe da existência das demais, e como se comunica com elas?
Para o compilador validar um código, ele não precisa deter a implementação de cada função ou variável chamada por esse código (esse papel é do
linker, numa etapa posterior à compilação). Para o compilador basta saber quais os nomes dos objetos válidos e quais os tipos de dados associados a cada um desses nomes. Sabendo o nome de uma função, o tipo de dados que ela retorna e os tipos dos seu argumentos, um programa pode invocá-la, e o compilador emite código corretamente, mesmo sem conhecer como a função é por dentro.
Normalmente, além da divisão em partes, um sistema escrito em C ou C++ também acaba tendo cada parte dividida entre interface, que contém as declarações necessárias para que os objetos de cada parte sejam conhecidos pelo compilador, e implementação, que é onde efetivamente estão os algoritmos que vão provocar a geração de código durante a compilação. Os arquivos de interface costumam ter o sufixo “.h”, que é uma abreviação de
headers (cabeçalhos), porque eles costumam conter os cabeçalhos das funções, sem o seu corpo.
Então essa coisa de compilação separada é só para programa grandes, certo?
Não.
Considere o seguinte programa (em C11, logo prescinde do “
return 0;” ao final).
#include <stdio.h>
int main(int argc, char **argv){
const char *name=argc<2? "World": argv[1];
printf("Hello, %s!\n", name);
}
Mesmo este programa simples (que é uma variação do clássico “Hello, World!”) usa compilação separada. O cabeçalho <stdio.h> contém apenas a declaração de
printf(), não sua definição. E também não se pode ver quem é que invoca a função
main(). Onde estão a implementação de
printf() e o código que interpreta os parâmetros recebidos do SO e monta os argumentos usados na invocação de
main()?
A resposta é que eles estão em bibliotecas pré-compiladas pelo fornecedor do seu sistema operacional e/ou compilador, que o
linker vai embutir no executável que ele gerar, depois de juntar a compilação do seu programa com essas partes que estão na biblioteca.