16. compilação e organização de arquivos

31
16. Compilação e Organização de Arquivos 16.1 Compilador X Interpretador Um código fonte pode ser compilado ou interpretado. Compiladores e interpretadores tratam o código de maneira diferente. Interpretador: Lê o código fonte, uma linha por vez, executando a instrução dessa linha. Deve estar presente toda vez que se quiser executar o programa. Ex.: Basic Como a cada execução, o código é examinado linha por linha, o processo é mais lento. Compilador: Lê o programa inteiro e o converte para código objeto. Código objeto é um código binário, também conhecido como código de máquina. Fica armazenado em um arquivo e pode ser executado pelo processador. O código compilado, após ser ligado, pode ser executado diretamente, sem necessitar de nova compilação e sem depender do compilador. 1

Upload: others

Post on 02-Jan-2022

6 views

Category:

Documents


0 download

TRANSCRIPT

ANEXO I 16.1 Compilador X Interpretador
• Um código fonte pode ser compilado ou interpretado. • Compiladores e interpretadores tratam o código de maneira
diferente.
• Interpretador: • Lê o código fonte, uma linha por vez, executando a
instrução dessa linha. • Deve estar presente toda vez que se quiser executar o
programa. Ex.: Basic • Como a cada execução, o código é examinado linha por
linha, o processo é mais lento.
• Compilador: • Lê o programa inteiro e o converte para código objeto. • Código objeto é um código binário, também conhecido
como código de máquina. Fica armazenado em um arquivo e pode ser executado pelo processador.
• O código compilado, após ser ligado, pode ser executado diretamente, sem necessitar de nova compilação e sem depender do compilador.
1
• Pré-processamento e ligação-edição são tarefas
executadas por dois programas, o pré-processador e o ligador respectivamente
• Em geral os compiladores mais novos contêm essas duas ferramentas acopladas.
1.6.21 - Pré-processamento
O pré-processamento é feito antes da compilação e consiste em: • Retirada de comentários • Inclusão de arquivos de cabeçalhos (headers) • Inclusão de macros no meio do código. • Algumas otimizações:
• Funções pequenas do mesmo arquivo são inseridas no meio do código, pois a chamada de funções é um processo caro
• Valores constantes calculados dentro de um loop são movidos para fora.
2
16.2.2 - Compilação
• As instruções são convertidas para código de máquina (código objeto ; extensão .o)
• É feita a verificação da sintaxe do código, erros de sintaxe são detectados nessa fase.
• Ligações com outras funções e variáveis externas não é feita. • As rotinas (bibliotecas) do sistema necessárias para executar
o programa ainda não são incluídas.
• Obs.: Bibliotecas do sistema: • Fornecem suporte em tempo de execução. • Permitem acesso a serviços do SO, ex.: I/O • Permitem acesso às rotinas de ponto flutuante.
• Durante a compilação de um programa, ocorrem os eventos de tempo de compilação. Exemplos: Avisar que uma variável não foi declarada.
• Código relocável: • Pode ser executado em qualquer região da memória
disponível. • Contém informações de quantos bytes, a partir do inicio
do arquivo, vai precisar para executar suas instruções. • A produção de código relocável facilita o processo de
ligação/edição.
3
16.2.3 - Ligação/edição
• Feita pelo ligador ou ainda linker ou loader. • O ligador é responsável por ligar (linkar) as várias partes do
código objeto: • códigos objeto gerados pelo programador • bibliotecas padrão da linguagem • rotinas (bibliotecas) do sistema.
• Após a ligação/edição é gerado o código executável. • Durante a ligação/edição são atribuídos os endereços das
instruções de “jump” (desvio) e “call” (chamadas), ou seja, resolvem-se as referências externas.
Exemplo: arquivo1.c arquivo2.c
int count; /*declaraçoes*/ #include <stdio.h> void display(void); extern int count; /* decl */ /*programa principal*/ /*função display*/ void main(void) void display(void) { { count = 10; printf(“%d \n”, count); display(); } }
• Na compilação são criados dois códigos objetos: arquivo1.o e arquivo2.o.
• A localização da função display() no arquivo 1 fica em aberto após a compilação. Idem para a variável externa count no arquivo
• Essas localizações (endereços) serão resolvidas durante a fase de ligação.
4
• O ligador “avisa” se algum símbolo está indefinido. Exemplos: • Uso de uma função que não foi definida. • Associação errada de bibliotecas.
• Os arquivos de biblioteca padrão (*.a) contêm um conjunto de códigos objetos (.o).
• Arquivos objetos são incluídos totalmente em um código executável.
• Arquivos de biblioteca são parcialmente incluídos. Somente as partes (*.o) que são utilizadas pelo programa são incluídas.
16.3 - Compilação separada
• Um programa pode estar contido em muitos arquivos.
• Se apenas uma parte do código é alterada, somente o arquivo correspondente necessita ser recompilado.
• A atualização e manutenção do programa é bem mais fácil e rápida.
• Porém existe o trabalho inicial de organizar o programa em diversos arquivos.
5
16.4 - Execução e mapa de memória
• Durante a execução de um programa, ocorrem os eventos de tempo de execução.
Ex.: erro de divisão por zero, causando a interrupção do programa.
• Um compilador também oferece rotinas para gerenciar o ambiente durante o tempo de execução.
• Durante a execução são criadas e utilizadas 4 regiões distintas na memória com finalidades específicas: • Região de armazenamento de código. • Região de armazenamento das variáveis globais. • Pilha:
Armazena informações relacionadas com funções, por exemplo: • endereço de retorno das chamadas às funções • argumentos de funções • variáveis locais
• Heap: • Região de alocação dinâmica. • Armazena dados criados em tempo de execução, ex.: listas
encadeadas, árvores. • A disposição física dessas 4 regiões varia em função do tipo da CPU e
do compilador.
• Colisão entre pilha e heap: • Funções recursivas são aquelas que chamam a si próprias. • A cada chamada, um novo conjunto de variáveis locais é criado e
armazenado na pilha. • Um grande número de chamadas recursivas podem “estourar” a
pilha e causar o problema de colisão entre pilha e heap. • Isto geralmente ocorre devido à erros de elaboração do código
fonte.
6
16.5 - Ambientes integrados de programação
• O processo de programar consiste basicamente em: • Criar o programa fonte através de um editor. • Compilar (pre-processamento, compilação e ligação/edição). • Fazer depuração através de um debbuger. • Executar o programa.
• Alguns compiladores, por exemplo: Turbo C e Borland C/C++, fornecem um ambiente integrado de programação contendo: • editor de texto • make: programa para organizar a compilação separada de
arquivos dependentes • compilador • debugger: permite acompanhar a execução do programa passo a
passo, verificando o valor de variáveis, endereços e expressões.
• Outros compiladores, por exemplo: gcc e cc do Unix, executam somente a tarefa principal de compilar
• No entanto existem alguns utilitários destinados a executar as outras tarefas. Alguns desses utilitários são: • vi e emacs: editores de texto. • make: funciona de modo semelhante ao make dos ambientes
integrados • xxgdb, dbxtool: auxiliam a depuração.
7
• Programas muito extensos devem ser colocados em diferentes arquivos.
• Vantagens: • É mais fácil trabalhar com arquivos pequenos. • Permite reutilização. • Se um arquivo com código fonte é modificado, somente
este é recompilado. • Os programadores do Unix utilizam uma maneira padrão para
particionar o código.
17.1 - Extensões
• Arquivos de programas C podem ter as seguintes extensões: • .c ou .C ⇒ código C • .cc ⇒ código C++ • .h ou .H ⇒ arquivos de cabeçalho (headers) em C ou C++
• Arquivos em código objeto têm a extensão .o • Arquivos de bibliotecas (vários .o) têm extensão .a • Arquivos executáveis têm extensão .exe (DOS) ou não sem
extensão.
8
17.2 - Arquivos fonte
17.2.1 - Disposição das informações As informações de um arquivo fonte devem ser dispostas na seguinte ordem:
• Comentário inicial contendo: • descrição e objetivo geral do arquivo • nome dos autores • data e outras informações importantes
• Inclusão de headers de bibliotecas na seguinte ordem: • bibliotecas padrão • bibliotecas criadas pelo programador. • Exemplo:
#include <stdio.h> #include <mybiblio.h>
• Definição de macros e tipos na seguinte ordem: • macros constantes (simples) • macros com argumentos • tipos (typedef) simples • tipos estruturados (typedef struct) • tipos enumerados (typedef enum)
• Declaração de variáveis na seguinte ordem: • externas • não estáticas • globais • estáticas globais
• Declaração de funções na seguinte ordem: • ordem alfabética se tiverem utilidade independente • agrupadas por utilidades afins
• Definição das funções
17.2.2 - Arquivos header (extensão .h)
• Os arquivos header são destinados a conter: • definições de macros e tipos, conforme o item 17.2.1 • declaração de variáveis e funções (protótipos), conforme
o item 17.2.1 • outros arquivos header (“include #<outros.h>“)
• Arquivos headers são incluídos, exatamente como estão escritos, no local onde é encontrada a palavra reservada #include ...
• Pode-se fazer a inclusão de um arquivo header em um outro arquivo de duas formas:
#include <nome.h> nome.h será procurado no diretório padrão de bibliotecas
ou #include “nome.h”
nome.h será procurado no diretório corrente
• Arquivos header contêm informações para uma finalidade específica, por exemplo: • <string.h> para manipular strings • <stdio.h> para manipular E/S • <math.h> para funções matemáticas
• headers estão associados a uma determinada biblioteca, ou seja, contêm definições e declarações que serão utilizadas pela mesma
• Uma biblioteca pode conter mais de um header associado.
10
• Exemplos: • stdio.h, string.h e outros são headers da biblioteca libc.a • O tipo FILE está definido em stdio.h • As funções de manipulação de arquivos (e outras) estão
declaradas em stdio.h • O tipo das funções de manipulação de aquivos que
utilizam o tipo FILE, estão definidas em libs.a
• Podem ser vistos como a interface de uma biblioteca, isto é, através dos headers pode-se verificar quais são os parâmetros das funções definidas na biblioteca correspondente.
• Lista de protótipos das funções: • São os tipos dos parâmetros e do valor devolvido pela
função • O padrão Ansi C, exige que esses tipos estejam
explicitados. • Durante a compilação é feita a verificação de tipos, ou
seja, é verificado se os parâmetros passados (quando a função é chamada) correspondem aos argumentos esperados (protótipos).
11
Exemplo: Seja o seguinte programa: #include <stdio.h> #include <string.h> char s1[ ] = “Alo, “; char s2[ ] = “ estou aqui!”; void main(void) { int p; p = strcat(s1, s2); printf(“ %s \n “, p); }
• No header string.h existe a seguinte declaração para a função strcat():
char *strcat(char *str1, const char *str2); • char * antes da função indica o tipo de valor retornado pela
função, ou seja, ponteiro para caracter. • No programa acima, o valor retornado é atribuído a p, que foi
declarada como int. • O compilador no padrão Ansi C vai acusar um erro ao fazer a
verificação de tipos, pois p deveria ter sido declarado como char * ao invés de int.
• Ao se criar headers, deve-se colocar no mesmo definições e declarações com uma finalidade comum.
• Alguns códigos são dependentes do hardware, como por exemplo, funções para manipular janelas, etc. Deve-se colocar código dependente do hardware em arquivos separados do código independente. Assim facilita a adaptação, só se mexe no arquivo que contém código dependente.
12
17.2.3 - Arquivos fonte (extensão .c)
• Contém as definições das funções feitas no header correspondente, bem como utiliza os tipos e variáveis especificados no mesmo.
• Outros tipos, variáveis e funções também podem ser declarados e/ou definidos nos arquivos .c
• Fontes e headers correspondentes possuem o mesmo nome, muda apenas a extensão.
Exemplo:
nome.h nome. c
• Um arquivo fonte .c não necessariamente precisa ter um header associado.
• Um arquivo fonte .c pode incluir vários headers.
13
pilha.h pilha.c
14
char letra; int num; } TipoItem;
typedef struct { TipoItem item; Elemento *prox; } Elemento;
/*declarações de funções */ void empilha( ..........); TipoItem desempilha(.........); void FPVazia(..........);
#include <pilha.h> void empilha(......) { ....... }
17.2.4 - Arquivos em código objeto
• Os arquivos .c estão associados aos headers correspondentes, logo tem-se que: arquivo.h + arquivo.c = arquivo.o
• Bibliotecas são arquivos que contêm módulos reutilizáveis pré-compilados que serão usados por desenvolvedores de aplicações.
• Bibliotecas: • possuem extensão .a • coleções de códigos objetos (extensão .o) • Exemplos:
libm.a contém o código objeto das funções declaradas em math.h libX11.a contém o código objeto das funções declaradas em X11.h
• Arquivos objetos: incluídos totalmente em um código executável. • As funções das bibliotecas C padrão estão contidas em bibliotecas (se
fossem em arquivos objetos, os programas seriam enormes).
• Elas podem ser : estática (static) ou compartilhada (shared). • Bibliotecas estáticas fazem parte do corpo do programa principal,
liberando-o assim do ambiente de configuração do sistema. • Bibliotecas compartilhadas ligam-se ao programa principal
dinamicamente, ou seja, um módulo só será ligado ao programa principal se for solicitado. Com isso, bibliotecas compartilhadas consomem menos recursos do sistema operacional além de facilitarem a substituição de módulos defeituosos sem a necessidade de compilar novamente todos os outros módulos ou sistemas envolvidos.
• archive (ar): programa que junta vários arquivos objetos (.o) em uma biblioteca (.a)
15
• Exemplo1: gerando uma biblioteca estática chamada libmods.a que inclui os dois arquivos objetos modulo1.o e modulo2.o
> gcc -c modulo1.c modulo2.c // compila e gera o arquivo.o
> ar -rcu libmods.a modulo1.o modulo2.o // gerando a biblioteca > ranlib libmods.a
> gcc -L. seuprog.c -lmods // compilando o programa com a sua biblitoeca.
Se você deseja disponibilizar a biblioteca para outras pessoas, incluindo você mesmo, crie um diretório para guardar suas bibliotecas (por exemplo, /usr/local/lib) e copie a biblioteca gerada para lá. Para compilar programas use:
> gcc -L/usr/local/lib seuprog.c -lmods
Exemplo 2: gerando uma biblioteca compartilhada "libmods.so" ===================
> gcc -fPIC -c modulo1.c modulo2.c // até aqui a biblioteca é estática
> gcc -shared -o libmods.so modulo1.o modulo2.o > chmod a+rx libmods.so
> gcc -L. seuprog.c -lmods // compilando o programa com a sua biblitoeca.
crie um diretório para guardar suas bibliotecas (por exemplo, /usr/local/lib) e copie a biblioteca gerada para lá. Para compilar programas use: gcc -L/usr/local/lib seuprog.c -lmods
16
Veja que o nome da biblioteca se incia com a prefixo lib.
O Linux usa o seguinte padrão para bibliotecas compartilhadas:
libaaa.so.b.c.ddd
libaaa.so é o nome da biblioteca; b é um número que indicará a maior versão; c é um número que indicará a menor versão; ddd é um número que informa a "release".
17
18 - Utilitários do Unix
18.1 Compiladores C • cc ⇒ compila código em C • gcc (Gnu C++)⇒ compila código em C e cm C++
• É melhor usar um compilador para C++ pois a verificação de tipos é feita com mais rigor, facilitando assim o trabalho do programador.
• Exemplos de utilização: • gcc nome.c ⇒ gera o arquivo executável de
nome ‘a.out’ • gcc nome.c -o saida ⇒ gera o arquivo executável de
nome ‘saida’ • gcc -c nome.c ⇒ gera o arquivo em código objeto
de nome ‘nome.o’ • gcc -lm ....... ⇒ incluir a biblioteca libm.a na
compilação
• gcc -Aa (ou -Ansi) ⇒compila em Ansi, isso se o “default” nao for Ansi.
• Mais detalhes: man gcc, man cc
18
18.2 - Make
• Make é um programa que mantém e atualiza programas e arquivos dependentes
• Os mesmos comandos utilizados em linha de comando podem ser utilizados dentro do arquivo de entrada do make
• Vantagem: • Se uma função de um arquivo é modificada, somente este
arquivo é recompilado. • Funcionamento básico:
• Para cada arquivo é verificado se a data de atualização é posterior a data de compilação.
• Se for posterior, compila novamente; caso contrário, não.
18.2.1 - Utilização • Para utilizar o make, deve-se construir um arquivo textual de
controle chamado makefile ou Makefile e a partir da linha de comando digitar make:
> make
• make procura no diretório corrente o arquivo de nome makefile ou Makefile e executa ações segundo as instruções desse arquivo.
> make -f Mymakefile • Neste caso o arquivo Mymakefile é executado e não o
default
19
18.2.2 - Formato do arquivo de controle
• Um arquivo makefile tem as seguintes partes: • macros (definições): são opcionais, isto é, um arquivo
makefile pode não conter definições • regras: parte obrigatória • comentários: também são opcionais
• <destino> depende de <dependencias> e é obtido através de <comandos> é o nome da regra, e é chamado de target.
• makefile contém a descrição textual de como os <destinos> são obtidos em função das dependencias.
• As várias dependencias são separadas por um ou mais espaços em branco ou por <TAB>s
• Os comandos devem estar separados do inicio da linha por um ou mais <TAB>s (obrigatoriamente)
• Cada linha será executada numa shell independente, linhas consecutivas devem ser unidas pelo caracter de continuação de linha \
• O programa make verifica recursivamente todas as dependências para cada destino, verificando se o mesmo deve ou não ser atualizado.
20
Definições
Regras
teste.c teste.h
arvore.h arvore.c main.c
arvore: arvore.o main.o gcc -lm -o arvore arvore.o main.o
arvore.o: arvore.c arvore.h gcc -c arvore.c
main.o: main.c arvore.h gcc -c main.c
#include <math.h> #include <arvore.h> etc....
#include<arvore.h>
pilha.c pilha.h lista.c lista.h fila.c fila.h main.c
makefile
• Comentários: # • Exemplos:
# um comentário no inicio da linha XX = 5 # comentário no fim
• Continuação de linha: \ • Exemplos:
22
main.o: main.c pilha.h lista.h fila.h gcc -c main.c
lislig:pilha.o fila.o lista.o main.o gcc pilha.o fila.o lista.o main.o -o lislig
#include <pilha.h> #include <lista.h> #include <fila.h> etc....
Exemplo: /* arquivo frase.h colocado em um diretório de include */ #include <stdio.h> int tamanho (char *); void inverte1 (char *); void inverte2 (char *);
/* arquivo inverte1.c */ void inverte1 (char *frase) { int i; char * pfrase = frase; while (*pfrase != '\0') putchar (*pfrase++); putchar ('\n'); while (--pfrase >= frase) putchar (*pfrase); putchar ('\n'); }
/* arquivo inverte2.c */ #include "include/frase.h" void inverte2 (char *frase) { int i; for (i=0; i<= (tamanho(frase)-1); i++) putchar (*(frase+i)); putchar ('\n'); for (i=tamanho(frase)-1; i>=0; i--) putchar (frase[i]); putchar ('\n'); }
23
/* arquivo tamanho.c */ int tamanho (char *str) { int i; for ( i=0; str[i]!='\0'; i++); return(i+1); }
/* arquivo main.c */ #include "include/frase.h" main () { char frase[] = "oi, como vai?"; printf ("%d\n", tamanho(frase)); inverte1(frase); inverte2(frase); }
Makefile 1 frase: main.o tamanho.o inverte1.o inverte2.o
gcc -ofrase main.o tamanho.o inverte1.o inverte2.o main.o: main.c include/frase.h
gcc -c main.c tamanho.o: tamanho.c include/frase.h
gcc -c tamanho.c inverte1.o: inverte1.c include/frase.h
gcc -c inverte1.c inverte2.o: inverte2.c include/frase.h
gcc -c inverte2.c
# o all é geralmente utilizado para marcar a primeira regra
all: inicial frase clean
# no caso de inicial e clean o nome da regra (ou target) # estão associados a uma acao a ser executada
inicial: @echo "Iniciando"
main.o: main.c include/frase.h gcc -c main.c
tamanho.o: tamanho.c include/frase.h gcc -c tamanho.c
inverte1.o: inverte1.c include/frase.h gcc -c inverte1.c
inverte2.o: inverte2.c include/frase.h gcc -c inverte2.c
#remove arquivos objetos clean:
@echo "Finalizando" @rm -rf *.o #@ faz com que o comando não apareça
25
• Macros: Servem para definir caminhos, opções de compilação, DIRETORIO = usr/prof/silvia/ED/arvores LIBD = lib/obj LIBFLAGS = -lm -lg
Para se utilizar as macros definidas, deve-se colocar o símbolo $ antes.
#Makefile 3
# definindo variaveis # @ faz o comando não aparecer na tela. CC=@gcc INC=./include/ OBJ=main.o tamanho.o inverte1.o inverte2.o
all: inicial frase clean
main.o: $(INC)frase.h main.c CC) -c main.c
tamanho.o: $(INC)frase.h tamanho.c $(CC) -c tamanho.c
inverte1.o: $(INC)frase.h inverte1.c $(CC) -c inverte1.c
inverte2.o: $(INC)frase.h inverte2.c $(CC) -c inverte2.c
#remove arquivos objetos clean:
26
• Substituição de sufixos: $(var: string1 = string2) • no valor de var, todas as ocorrências de string1,
serão substituídas pela string2 • string1 é um sufixo de var. • Exemplo1:
Sejam as seguintes definições: ARQH = pilha.h lista.h fila.h
e ARQO = $(ARQH:h=o)
• Exemplo2: Sejam as seguintes definições:
XX = a.c b.c c.c e
YY = $(XX:.c=_x.o) então $(YY) equivale a
a_x.o b_x.o c_x.o
#Makefile 4
# definindo variaveis CC=@gcc INC=./include/ SRC=$(wildcard *.c) #SRC = todos os arquivos .c do diretorio
all: inicial frase clean inicial:
@echo "Iniciando"
#expande SRC e substitui os.c por arquivos de mesmo nome.o frase: $(SRC:.c=.o)
$(CC) -ofrase $(SRC:.c=.o)
#remove arquivos objetos clean:
28
• Variável dinâmica (internas): # S@ nome da regra corrente # S^ dependência anterior # S< pega o primeiro valor da lista de dependências anterior. # $? lista de dependências mais recentes que a regra. # $* nome do arquivo sem sufixo
$@ • Toma o valor do destino (regra) corrente. • Exemplo: Os seguintes arquivos makefile são
equivalentes:
• Substituição de padrões: $(var: op % os = np % ns)
• no valor de var, todas as ocorrências do prefixo op, serão substituídas por np
• todas as ocorrências do sufixo os serão substituídas por ns.
• Exemplo: Sejam as seguintes definições:
XX = xx_a.c xx_b.c xx_c.c e
YY = $(XX:xx_%c = %o) então $(YY) equivale à
a.o b.o c.o
xxx: yyy.c zzz.c gcc -o $@ yyy.c zzz.c
#Makefile 5
# definindo variaveis CC=@gcc INC=./include/ SRC=$(wildcard *.c) #SRC = todos os arquivos .c do diretorio
all: inicial frase clean inicial:
@echo "Iniciando"
#expande SRC e substitui os.c por arquivos de mesmo nome.o #variaves internas # S@ nome da regra == frase # S^ dependencia anterior == $(SRC:.c=.o) # o comando abaixo pode ser então reescrito # frase: $(SRC:.c=.o) # $(CC) -ofrase $(SRC:.c=.o)
frase: $(SRC:.c=.o) $(CC) -o $@ $^
main.o: $(INC)frase.h main.c $(CC) -c main.c
tamanho.o: $(INC)frase.h tamanho.c $(CC) -c tamanho.c
inverte1.o: $(INC)frase.h inverte1.c $(CC) -c inverte1.c
inverte2.o: $(INC)frase.h inverte2.c $(CC) -c inverte2.c
clean: @echo "Finalizando" @rm -rf *.o
30
#Makefile 6
# definindo variaveis CC=gcc INC=./include/ SRC=$(wildcard *.c) #SRC = todos os arquivos .c do diretorio
all: inicial frase clean inicial:
@echo "Iniciando" #expande SRC e substitui os.c por arquivos de mesmo nome.o
#variaves internas # S@ nome da regra == frase # S^ dependencia anteriror == $(SRC:.c=.o) # S< pega o primeiro valor da lista de dependencias anterior. # $? Lista de dependências mais recentes que a regra. # $* Nome do arquivo sem sufixo # o comando abaixo pode ser então reescrito # frase: $(SRC:.c=.o) # $(CC) -ofrase $(SRC:.c=.o)
frase: $(SRC:.c=.o) $(CC) -o $@ $^
# % indica um padrão, fazer para todo .o e .c %.o: %.c $(INC)frase.h
$(CC) -c $< -o $@
31
16.5 - Ambientes integrados de programação
17 - Organização de arquivos no UNIX
17.1 - Extensões
18 - Utilitários do Unix