A Aldeia Numaboa ancestral ainda está disponível para visitação. É a versão mais antiga da Aldeia que eu não quis simplesmente descartar depois de mais de 10 milhões de pageviews. Como diz a Sirley, nossa cozinheira e filósofa de plantão: "Misericórdia, ai que dó!"

Se você tiver curiosidade, o endereço é numaboa.net.br.

Leia mais...

Tutoriais e Programação

Linguagem C - Bibliotecas e Tipos

Qui

27

Nov

2008


20:23

(38 votos, média 4.21 de 5) 


C

A imensa coleção de funções que o sistema operacional do Windows nos oferece, a assim chamada API (Application Programming Interface), facilita muito nossa programação se soubermos exatamente como usar cada função. Ler a descrição técnica é essencial para saber, entre outras coisas, o número de parâmetros exigidos, o tipo destes parâmetros e o valor de retorno da função. Afinal de contas, como programadores, o mínimo a fazer é se familiarizar com a interface que nos é oferecida.

As bibliotecas padrão

Para inserir funções da API nos nossos programas é preciso indicar ao pre-processador onde ele poderá encontrá-las. Sabemos que funções da API do Windows ficam agrupadas em arquivos próprios de acordo com o tipo, numa espécie de biblioteca de funções. Estas bibliotecas são aquivos que possuem a extensão .dll, chamados simplesmente de DLLs.

Quando queremos usar uma função da API, ou uma função própria da linguagem C, não escrevemos a função no nosso programa. É muito mais prático pedir ao pre-processador que inclua o código da função desejada. Para isto, precisamos fornecer ao pre-processador um "mapa da mina", para que ele possa localizar e incluir a função desejada. O lcc-win32 possui vários "mapas" prontinhos para serem utilizados, arquivos com a extensão .h chamados de cabeçalhos e que se encontram no diretório /lcc/include. Os principais são:

CabeçalhoUso
stdio.h

Standard Input Output (entradas e saídas padrão): este cabeçalho contém a definição da estrutura FILE, usada para todas as entradas (input) e saídas (output), além das definições de todas as funções que lidam com a abertura, fechamento, etc de arquivos. A famosa função printf também é definida aqui, juntamente com sprintf, fprintf e toda a família de funções relacionadas.

math.h

Funções Matemáticas: sin, cos, atan, log, exp, etc. Aqui encontramos trigonometria (sin, cos, tan, atan, etc), arredondamentos (ceil, floor), logaritmos (log, exp, log10, etc), raiz quadrada e cúbica (sqrt, cbrt) e constantes como pi, e, etc.

stdlib.h

Standard library functions (funções da biblioteca padrão): Contém abort (término anormal do programa), exit (término normal), atoi, itoa (conversão de texto para inteiro), malloc, calloc, free (módulo de memória dinâmica), rand, srand (números randômicos), putenv, getenv (administração do ambiente), qsort (ordenação), strtod, strtol (conversão de string para double/long), sleep (suspender a execução por um certo período de tempo).

stddef.h

Este arquivo define macros e tipos de uso geral em programas: NULL, offsetof, ptrdiff_t, size_t e muitos outros.

string.h

Manipulação de strings: aqui são definidas todas as funções que lidam com a representação padrão de como as strings são usadas em C. Temos strcmp (comparação de strings), strlen (obtenção do comprimento de uma string), strcpy (cópia de uma string para outra), strcat (concatenação de strings), strstr (substring numa string), memset (atribuição de uma região RAM para um caracter), memcpy (copiar memória), memmove (copiar memória cuidando da região de sobreposição).

windows.h

Todas as definições de janelas: criar, abrir, etc. É um arquivo cabeçalho grande com cerca de 500 mega de definições. Saiba que o lcc-win32 incorpora neste arquivo muitos dos arquivos que normalmente são individualizados em outras distribuições (como o winbase.h, por exemplo).

Se você tiver curiosidade de saber como são montados estes arquivos de cabeçalho, basta abrí-los em qualquer editor de texto (o do lcc-win32 também serve).

Os tipos padrão

A linguagem C possui os seguintes tipos padrão:

TipoTamanhoDescrição
_BOOL1Tipo lógico, pode ser 0 ou 1.
char1Tipo caracter, podendo ser com sinal ou sem sinal.
short2Inteiro armazenado em 16 bits, com ou sem sinal.
int4Inteiro armazenado em 32 bits, com ou sem sinal.
long4Idêntico ao int.
long long8Inteiro armazenado em 64 bits, com ou sem sinal.
float4Ponto flutuante de precisão simples (cerca de 7 dígitos).
double8Ponto flutuante de precisão dupla (cerca de 15 dígitos).

Manifestos e definições

É uma confusão danada! "Declaration" em Inglês é "manifesto" e "Statement" é "declaração". É muito importante entender a diferença entre um manifesto e uma declaração (ou definição) na C.

Um manifesto apresenta um identificador ao compilador. É como se um manifesto dissesse "este identificador é o XXX e ele será declarado (definido) mais adiante". Um manifesto pode ser, por exemplo:

extern double sqrt(double);

Com este manifesto apresentamos o identificador sqrt ao compilador, dizendo que se trata de uma função que usa um argumento de precisão dupla (double) e que retorna um resultado de precisão dupla (double). A apresentação pára por aí e nem ocupa espaço. É que, se esta função não for utilizada pelo programa, ela nem será incorporada - portanto, não ocupará espaço no executável.

Uma declaração (definição) diz ao compilador para alocar espaço para o identificador. Por exemplo, para definir a variável "contador":

int contador;

Neste caso, o compilador cria um espaço na área de variáveis locais da função que contenha esta definição, abrindo espaço suficiente para conter um número inteiro.

O que precisa ficar bem claro é que uma variável pode ser manifestada quantas vezes quisermos, mas só deve ser definida num único ponto. É o mesmo que dizer que, quando definimos uma variável, emitimos sua "carteira de identidade" (que precisa ser única) e fixamos sua residência (para que possamos encontrá-la quando for preciso). Quando manifestamos uma variável (ou uma função), dizemos apenas que deve aparecer uma "moça" de nome tal, ou um "rapaz" de nome tal, ou um int ou um double de nome tal... enfim, uma entidade de nome tal cujo tipo seja o que foi manifestado - mas que ainda está sem lenço e sem documento.


Manifestando e definindo variáveis

Uma variável é definida com . Se quisermos apenas manifestar a variável, sem alocar espaço para ela, adicionamos a palavra-chave extern. Além disto, é possível definir uma variável e, simultaneamente, atribuir-lhe um valor. Veja alguns exemplos:

int a; int b = 3; double d = (1024*1024)/16; extern long long h;

No exemplo acima, a variável h, de 64 bits, foi apenas manifestada. As restantes foram (manifestadas e imediatamente) definidas, sendo que a variável a não recebeu qualquer valor, a variável b recebeu o valor 3 e a variável d recebeu o valor de uma operação de multiplicação e divisão.

Ponteiros (que apontam para endereços) são manifestados ou definidos com asterisco. Tomemos a variável b como exemplo: se quisermos o valor de b, referenciamos b pelo "nome" e obtemos o valor 3 (nome é b e seu valor é 3). Mas, se quisermos saber em que endereço de memória foi armazenado o valor de b, usamos *b.

Para economizar digitação podemos colocar variáveis do mesmo tipo, separadas por vírgulas, numa única linha. Apenas para manter a ordem, é aconselhável não misturar ponteiros com outros inteiros:

int a, contador, base, c; int *enderecoDaBase, *m, *pontA;

Manifestando funções

O formato padrão do manifesto de funções é (, … );

Mas porque manifestar funções? Não seria mais rápido e prático defini-las diretamente e usá-las? Aí depende... veja o código abaixo:

Módulo A Módulo B int funcTeste(int a) ... { funcTeste(7, 9); return a + 8; ... }

Se criarmos diretamente a função funcTeste no módulo do programa A e, no módulo do programa B, inadvertidamente chamarmos a função com parâmetros que não são os que foram definidos, o compilador não tem como identificar o erro. Vai tudo muito bem até que se resolva executar o programa que, obviamente, vai dar pau. Para que o compilador possa checar todas as chamadas de funções, é preciso manifestá-las antes de defini-las.

Funções apenas manifestadas são chamadas de PROTÓTIPOS de função. No exemplo acima, se funcTeste tivesse um protótipo, o compilador estrilaria quando estivesse checando a chamada no módulo B, avisando que a chamada está incorreta. Apenas uma linha de protótipo pode economizar horas de debug quando tentamos encontrar um erro que só aparece em tempo de execução. Pense nisso!

Agora imagine que, para se garantir, você tenha que escrever os protótipos de todas as funções da linguagem C e da API do Windows que forem usadas pelo seu programa. Uma loucura! É aí que entram os arquivos cabeçalho, aqueles com a extensão .h e que se encontram no diretório /lcc/include/. Estes arquivos nada mais são do que coleções de protótipos. Basta incluir os cabeçalhos necessários com #include e ganhamos um monte de tempo. Graaaaande Jacob Navia, autor do lcc-win32, que forneceu o pacote completo!

Definindo funções

Definir funções tem o mesmo jeitão do manifesto de funções. Uma das diferenças é que, ao invés de usar ponto e vírgula, adicionamos um bloco de outras declarações delimitadas por colchetes. A outra diferença é que os argumentos precisam receber um nome (ou identificador). Estes identificadores são imprescindíveis porque apenas através deles é que poderemos acessar os argumentos. Um exemplo bem simples seria:

int SomaUm(int entrada) { return entrada + 1; }

Observações da vó

Eu sei, este módulo foi um pouco sem graça porque não teve nenhum exemplo para brincar. Acontece que determinados conceitos são fundamentais se quisermos avançar com alguma segurança. Para compensar a falta de "brinquedinhos", os próximos módulos vão fazer a festa da garotada (e da adultada também wink )

Mas nem tudo foi pedreira. Se você entendeu o que é (e para que serve) um protótipo de função, então a linha numerada com 4/5, que consta do nosso programa dlg2.c, deixou de ser uma incógnita:

... #include "testedlgres.h" static BOOL CALLBACK DialogFunc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); static char balaio[1024]; ...

Para compensar a falta de exemplos neste tutorial, o próximo é sobre uma "janela de verdade". Não se preocupe com os detalhes porque, à medida que for necessário, explicações mais detalhadas serão dadas. Prometo vovo

Логофет Вадим Геннадьевичгриль на газу ценалобановский александр женаустановка ssdотзыв написатьvsemsmart broker mfx

Informações adicionais