Pré-processador
![](http://upload.wikimedia.org/wikipedia/commons/thumb/9/9a/Preprocessor.png/220px-Preprocessor.png)
Um pré-processador é um programa que recebe texto e efectua conversões léxicas nele. As conversões podem incluir substituição de macros, inclusão condicional e inclusão de outros ficheiros.
A linguagem de programação C possui um pré-processador que efectua as seguintes transformações:
- substitui trigrafos por equivalentes
- concatena ficheiros de código-fonte
- substitui comentários por espaços em branco
- reage a linhas iniciadas com um caracter de cardinal (#), efectuando substituição de macros, inclusão de ficheiros, inclusão condicional e outras operações
O uso de pré-processadores tem vindo a ser cada vez menos comum à medida que as linguagens recentes fornecem características mais abstractas em vez de características orientadas lexicalmente. É certo que o abuso do pré-processador pode dar origem a código caótico. Ao desenhar uma linguagem de programação baseada em C, Bjarne Stroustrup introduziu características tais como funções em linha e modelos na linguagem C++ numa tentativa de tornar o pré-processador de C menos relevante. Há também linguagens recentes que tem pouca ou nenhuma funcionalidade de pré-processador, como por exemplo a linguagem Java, que não possui um pré-processador. O pré-processamento pode ser bastante incómodo ao implementar-se análise gramatical incremental ou análise léxica incremental, pois alterações às regras de pré-processamento podem afectar por completo o texto a ser pré-processado.
Exemplos de C
- Um exemplo típico em C é:
# include <stdio.h> # define FOO 0 int main (void) { /* versão alterada do programa "olá mundo" */ printf("Olá, Mundo!\n"); return FOO; }
O pré-processador de C, ao analisar este código-fonte, efectua as seguintes alterações:
- substitui a linha
#include <stdio.h>
pelo ficheiro-cabeçalho com aquele nome, o que torna possivel a utilização da subrotina printf(). - define o conjunto de caracteres FOO para que quando executado seja interpretado como 0.
- substitui o texto comentado (texto entre simbolos
/*
e*/
por espaço em branco. - substitui o termo
FOO
na expressãoreturn FOO;
por0
- substitui a linha
- Outro exemplo de um recurso bastante comum, conhecido por "Include Guards", utilizado em arquivos header:
# ifndef _LIBRARY_H # define _LIBRARY_H /* Todo código que define o conteúdo deste arquivo header: assinatura de funções, definição de constantes, etc... */ # endif
Isso garante que um determinado arquivo header será incluído apenas uma vez durante a compilação de um projeto. A primeira vez que for encontrado #include <library.h>
o símbolo _LIBRARY_H não estará definido, portanto #ifndef
será verdadeiro e o próximo passo executado pelo compilador será definir esse símbolo _LIBRARY_H e compilar todo código. Caso haja, em outro arquivo .c
pertencente ao mesmo projeto, a diretiva #include <library.h>
, então dessa vez #ifndef _LIBRARY_H
será falso e nada deste arquivo header será compilado novamente. Caso essas diretivas de compilação condicional não estivessem presentes seriam gerados erros de compilação ao incluir mais de uma vez o mesmo arquivo header.
- Mais outro recurso, pré-processado, é o uso da diretiva
#pragma
, cuja função é prover informações adicionais ao compilador além do que é coberto pela própria linguagem. A seguir temos um exemplo que instrui o compilador a utilizar um alinhamento dos dados em memória diferente do alinhamento padrão:#pragma pack(n)
. O parâmetron
indica a quantidade de bytes que deve ser utilizada para alinhamento e deverá ser um número potência de 2 (2,4,8,16,32,64,...), caso não seja passado o parâmetro será utilizado o packing padrão do compilador.
#include <stdlib.h> #include <stdio.h> #pragma pack(2) typedef struct person t_person; struct person { short int id; int sector; short int age; }; int main ( int argc, char *argv[] ) { printf("sizeof t_person: %ld\n", sizeof(t_person)); return EXIT_SUCCESS; }
Compile, execute e verifique a saída que mostra o tamanho da estrutura t_person
em bytes. Experimente não passar nenhum parâmetro para a diretiva #pragma pack()
, compile e execute. O tamanho da estrutura será diferente já que utilizando o packing padrão do compilador são adicionados dados sem significado (padding).
Referências
- «pragma C++ Reference». www.cppreference.com. Consultado em 21 de abril de 2012
- «Pragmas - The C Preprocessor». gcc.gnu.org. Consultado em 21 de abril de 2012
![]() | Este artigo sobre programação de computadores é um esboço. Você pode ajudar a Wikipédia expandindo-o.
|