Programar em C/Bibliotecas
Bibliotecas
[editar | editar código-fonte]Bibliotecas são conjuntos de funções que foram feitas por alguém e que podem ser usadas por outros programas sem que nos preocupemos com o código dessas funções.
Além da vantagem de organizar o código, bibliotecas também têm a vantagem de poderem ser utilizadas em vários programas sem necessidade de copiar grandes trechos de código; basta dizer ao compilador que queremos adicionar aquela biblioteca ao executável.
Por exemplo, vamos tentar criar a nossa própria biblioteca, com duas funções: uma para gerar números (pseudo-)aleatórios e uma para calcular o valor de pagamento de uma amortização com juros compostos. Também incluiremos uma função para gerar um número inicial a partir da hora atual, o que fará com que as seqüências de números não sejam sempre as mesmas.
Chamaremos a biblioteca de teste1.
#include <math.h>
#include <time.h>
int rand_seed = 10;
/* Gerador de números pseudo-aleatórios */
int rand ()
{
rand_seed = rand_seed * 1103515245 + 12345;
return (unsigned int) (rand_seed / 65536) % 32768;
}
void init_seed ()
{
rand_seed = time (NULL);
}
/* Cálculo do valor de cada pagamento de uma amortização
* Dados: vp = valor presente;
* n = número de pagamentos;
* i = taxa de juros (em formato decimal)
*/
double vf (double vp, int n, double i)
{
return (vp * i * pow (1 + i, n - 1) /
(pow (1 + i, n) - 1));
}
As linhas acima são o arquivo do código da nossa biblioteca. Abaixo está o código de um programa que testará essa biblioteca. Lembre-se de que os dois trechos devem estar em arquivos separados.
#include <stdio.h>
int main()
{
int r1, r2, n_pgtos;
double a_vista, juros, v_pgto;
r1 = rand ();
r2 = rand ();
printf ("Números aleatórios: %d, %d\n\n", r1, r2);
printf (" Valor à vista: ");
scanf ("%lf", &a_vista);
printf ("Número de pagamentos: ");
scanf ("%d", &n_pgtos);
printf (" Taxa de juros: ");
scanf ("%lf", &juros);
juros /= 100; /* converte a porcentagem em número */
v_pgto = vf (a_vista, n_pgtos, juros);
printf ("Valor de cada pagamento: %lf\n", v_pgto);
return 0;
}
Algo que você deve ter notado é que nesse arquivo não demos nenhuma informação sobre as funções vf e rand nele usadas. Realmente, se você tentar compilar o código como está, o compilador dará um aviso; mas ao tentar criar o executável, o montador não poderá continuar pois não recebeu nenhuma informação sobre onde as funções estão.
Para isso, precisamos realizar três passos adicionais antes de compilar o programa teste:
- Fazer um arquivo-cabeçalho com informações sobre as funções. Esse arquivo será incluido com a diretiva #include, da mesma maneira que cabeçalhos padrão como "stdio.h" ou "math.h".
- Compilar a biblioteca separadamente.
- Instruir o compilador/montador a procurar pela biblioteca ao compilar o programa teste.
O arquivo-cabeçalho
[editar | editar código-fonte]Arquivos-cabeçalho são arquivos que contém informações que servem para o compilador reconhecer funções ("VER: convenções para chamadas a funções ou calling convention"), macros, tipos de dados e variáveis que não estão no arquivo sendo compilado. Esses arquivos costumam ter a extensão ".h" — é o caso, por exemplo, dos cabeçalhos padrão stdio.h e math.h. A letra H é usada pois é a inicial de header (cabeçalho em inglês).
Em uma biblioteca, os cabeçalhos contêm, os protótipos das funções disponibilizadas pela biblioteca e, quando necessário, sobre os tipos de estruturas usados. Bibliotecas mais complexas costumam dividir essas funções entre vários arquivos.
Para fazer nosso próprio cabeçalho, precisamos colocar as declarações das funções disponíveis na biblioteca:
int rand ();
void init_seed ();
double vf (double, int, double);
Se você se lembra da última lição, poderá sugerir que coloquemos algumas linhas a mais:
#ifndef _TESTE1_H
#define _TESTE1_H
int rand ();
void init_seed ();
double vf (double, int, double);
#endif
Agora, sempre que precisarmos usar a biblioteca teste1, basta incluir o arquivo teste1.h no início do nosso programa:
#include "teste1.h"
Note que se o cabeçalho estiver instalado nos diretórios padrão do compilador ou do sistema, você deve trocar as aspas pelos sinais de menor/maior (< ... >).
Compilação da biblioteca
[editar | editar código-fonte]Tendo salvo o código da biblioteca no arquivo teste1.c, você deve compilar a biblioteca.
No GCC
[editar | editar código-fonte]- Compile o arquivo-fonte normalmente, mas sem gerar o executável:
gcc -c teste1.c -o libteste1.o
- Crie o arquivo da biblioteca com o comando ar. Você ainda não o conhece, mas a sintaxe é simples: basta digitar ar rv, seguido do nome do arquivo da biblioteca e depois dos nomes dos arquivos-objeto a serem incluídos (separados por espaços). No GCC, as bibliotecas estáticas costumam ter o nome "libnome.a".
ar rv libteste1.a libteste1.o
No MS Visual C++
[editar | editar código-fonte]No Visual C++, o nome padrão das bibliotecas é "nome.lib", assim como em vários outros compiladores para Windows. Nele, os comandos correspondentes aos dois passos acima são:
cl /c teste1.c lib /out:teste1.lib teste1.obj
Compilação do programa
[editar | editar código-fonte]Após criar o arquivo objeto libteste1.o com o comando ( gcc -c teste1.c -o libteste1.o ) e a biblioteca estática com o comando "ar" , você deve instruir o compilador com as opções de edição de links para poder incluí-la no seu programa:
- No GCC:
gcc main.c -L. -l libteste1.a -o main.bin -lm
Note as opções que você não conhecia: -L e -l . A primeira indica em que diretório deve ser procurada a biblioteca; o ponto indica o diretório atual. Se essa opção for omitida, o compilador procurará apenas nos diretórios padrão. A segunda é uma opção do editor de links indicando uma biblioteca a ser incluída; o compilador procurará pelo arquivo adicionando o prefixo lib e a extensão .a, daí a necessidade de dar o nome "libteste1.a" à biblioteca. Mais bibliotecas podem ser incluídas como a -lm que neste caso serve para chamar a biblioteca math do math.h, sem este comando ele poderá apresentar um erro na hora da compilação.
- No Visual C++:
link /out:main.exe main.obj teste1.lib
Note que nesse caso simplesmente especificamos os arquivos que devem ser montados. O diretório de procura pode ser especificado pela opção /libpath:diretório.