terça-feira, 15 de maio de 2007

SD ou SDHC?

Estou planejando comprar um cartão de memória novo para o meu palm. Resolvi que comprarei de 4GB. Bem, quando fui pesquisar vi que existe uma tremenda confusão quanto aos tipos de cartão SD/SDHC. Alguns dizem que só pode existir SD até 2GB e que a partir de 4GB só SDHC. Pois bem, depois de muita indecisão sobre o que comprar e dúvidas se seria compatível com meu palm ou não cheguei a algumas conclusões:
  • Existem, sim, cartões SD de 4GB;
  • A grande questão é que este tipo de cartão não é padronizado, sendo assim, cada fabricante faz seu cartão da maneira que melhor entender e, portanto, não há como ter garantias de que qualquer cartão SD de 4GB irá funcionar com qualquer aparelho;
  • Por outro lado, os SDHC de 4GB são padronizados (da mesma forma que os SD até 2GB), sendo assim, qualquer cartão SDHC de 4GB funcionará com qualquer aparelho que aceite este tipo de cartão;
  • Outro ponto é que, aparelhos que aceitem cartões SD podem também ser compatíveis com os SDHC (já que possuem o mesmo tamanho e formato) através de atualizações dos drivers do dispositivo para que possa reconhecer o novo formato;
  • No fórum 1src já se discute até a possiblidade de reconhecer cartões de 8GB. Dmitry Grinberg, criador do famoso UDMH afirmou fazer funcionar um cartão de 8GB em seu TX, porém não afirmou se está se tratando de um SD ou SDHC;

Bem, é isso, com essas informações acho que já posso comprar meu cartão de 4GB tranquilo. ^.^

sábado, 12 de maio de 2007

C++ STL (Standard Templates Library) - Parte 1

Standard Templates Library

A STL, Standard Templates Library ou Biblioteca Padrão de Gabaritos (também achei esquisito, mas é esse nome mesmo), é uma biblioteca que provê as estruturas de dados e algoritmos básicos para a Ciência da Computação. É uma biblioteca genérica onde todos os seus componentes são parametrizáveis, ou seja, cada função é feita para aceitar diversos tipos de entrada diferente e operar sobre esses dados, desde que estes tipos suportem determinadas funções básicas. Todos os componentes da STL são templates (ou gabaritos). Elas nos poupam da tarefa de reimplementar o código para cada novo tipo de dado da aplicação. Por isso, é necessário ter conhecimento de templates em C++ para entender e usar a STL. A STL oferece Containers (recipientes), Iterators (iteradores) e Algorithms (algoritmos).

Containers (Recipientes)

Como o próprio nome já sugere, recipientes ou containers são onde os dados serão armazenados, pode-se pensar neles como uma caixa onde os dados serão colocados la dentro. Containers podem ser classificados como:
  • Seqüências de dados;
  • Recipientes associativos para pares de objetos (chave, dado);
  • Adaptadores que provêem um subconjunto da funcionalidade de um recipiente (Pilhas, filas, filas de prioridade).
Iterators (Iteradores)

Iteradores são as estruturas usadas para percorrer e/ou acessar os elementos contidos em um recipiente de maneira unificada. Estas estrutras escondem os detalhes de implementação, principalmente ponteiros, das aplicações. Com isto, além de a programação ser facilitada fica menos propensa a erros. Portanto, geralmente é possível trocar o tipo de recipiente e ainda assim usar o mesmo código.

Algorithms (Algoritmos)

A STL possui inúmeros algoritmos prontos para se usar, sendo que estes algorimos recebem como entrada tipicamente recipientes e normalmente, o processamento efetuado utiliza somente iteradores, nada de ponteiros. Ordenação, busca, contagem, substituição, etc... Iteradores tem operadores de incremento "++" definidos. Ponteiros podem ser usados como iteradores. A STL adota a filosofia de manter os algoritmos fora das classes dos recipientes, pois assim permite que o mesmo algoritmo possa agir sobre recipientes diferentes.

Referências
[1] Standard Template Library Programmer's Guide
[2] C++ Standard Templates Library: A Tutorial and Reference

quinta-feira, 19 de abril de 2007

Makefiles

O que vem a ser Make?

Make é um programa que trabalha com uma arquivo chamado makefile ou Makefile. Dentro deste arquivo são declaradas variáveis, dependências e regras que servirão para o propósito de compilação de vários tipos diferentes de arquivos (C, C++, Phyton, PostScript, etc). A utilização do make traz grandes vantagens para o programador, tais como:
  • Evitar a digitação de comandos longos toda vez que um projeto tiver que ser recompilado;
  • Evitar o esquecimento de parâmetros utilizados raramente na compilação e que possivelmente podem ser esquecidos;
  • Manter o ambiente de desenvolvimento consistente;
  • Automatizar o processo de construção/compilação.
Formato dos Makefiles - Variáveis

Para efetuar a declaração de variáveis dentro de um makefile, simplesmente deve-se colocar o nome desejado para ela em letras maiúsculas seguido do sinal de igualdade e posteriormente o valor desejado

NOMEVAR = Valor

Assim é feita a atribuição de Valor à variável NOMEVAR. Pode-se definir, ainda, como valores de variáveis parâmetros de compilação ou mesmo o nome do compilador escolhido para ser utilizado.

PARAM = -o
CXX = g++

Isto atribui o parâmetro de compilação -o à variável PARAM e o nome do compilador g++ à variável CXX. Para acessar o conteúdo de uma variável, colocasse um cifrão($) seguido do nome da variável entre parentesis.

$(NOMEVAR)

Retornando, assim, o valor Valor. Da mesma maneira pode-se accesar o valor da variável PARAM e do compilador escolhido.

$(PARAM)
$(CXX)

Formato dos Makefiles - Dependências

Dependencias são o "coração" dos makefiles. Sem eles nada será feito. O formato geral para declaração de dependências é como se segue:

dependencia: dependencia1 dependencia2 ... dependenciaN
          comandos para a dependencia

É importante ressaltar que antes dos comandos para a dependencia é necessária a colocação de uma tabulação(tab), e não espaços, como pode parecer. A forma de leitura desse arquivo é exatamente verificar cada dependência e as dependências que ele possui. O que o make faz é verificar dependencia e perceber que ela é dependende de dependencia1, dependencia2 ... dependenciaN. Após isso ele vai atras da definição de cada uma dessas dependências para poder, ao final, executar os comandos do alvo1. Por exemplo:

main: programa.cc
          g++ programa.cc -o programa

Este é um exemplo bem simples, onde pode-se perceber a maneira que o make atua. Ao chamar o make ele automaticamente compila as dependências de main, por que é a primeira dependencia contido no arquivo makefile. Com isso, ele checa programa.cc para verificar quando se deu a última modificação nesse arquivo e determinar se é necessário executar os comandos correspondentes (g++ programa.cc -o programa). Se o arquivo não tiver sido modificado após a última compilação, nada será executado.

Um outro exemplo, onde pode-se perceber essas dependências mais claramente é no desenvolvimento de vários arquivos, onde o principal depende de vários outros. Sendo assim, na declaração da primeira dependência coloca-se como dependentes os outros arquivos objeto que são gerados dos outros arquivos, e na dependência desses respectivos arquivos os comandos de compilação para eles. Fazendo como a seguir:

programa: main.cc subarquivo.o classe.o
          g++ main.cc subarquivo.o classe.o

subarquivo.o: subarquivo.cc classe.o
          g++ -c main.cc subarquivo.o classe.o

classe.o: classe.cc
          g++ -c classe.cc

Obervemos as dependências aqui. Quando o make é executado, a dependência programa é a primeira a ser chamada. Então, a dependência subarquivo.o é encontrada, logo após, classe.o é encontrada dentro de subarquivo.o. Classe.cc é, então, compilada, a seguir subarquivo.o é compilado, então, finalmente podemos retornar à dependência programa. Todas as três dependências estão compiladas e, finalmente, os comandos de programa são efetuados para criar a.out.

Amarrando variáveis e dependências

Podemos usar valores de variáveis dentro de dependências muito facilmente. No próximo exemplo, utilizamos duas variáveis, uma para definir o compilador e outra para definir as opções de compilação. Isto facilita muito a vida quando queremos, por exemplo, habilitar o depurador para todo o código ou desabilitá-lo, se assim preferirmos.

CXX = g++
FLAGS = -g

program: main.cc subarquivo.o classe.o
          $(CXX) $(FLAGS) main.cc subarquivo.o classe.o

subarquivo.o: subarquivo.cc classe.o
          $(CXX) $(FLAGS) -c main.cc subarquivo.o classe.o

classe.o: classe.cc
          $(CXX) $(FLAGS) -c classe.cc

Surge a pergunta: como faremos para limpar isto? A resposta é simples, basta adicionar ao makefile uma nova dependencia chamada "clean", a qual se encarregará de limpar todo nosso código e recomeçar do que tinhamos antes, ou seja, somente os arquivos fonte. A dependência é feita como se segue:

CXX = g++
FLAGS = -g

program: main.cc subarquivo.o classe.o
          $(CXX) $(FLAGS) main.cc subarquivo.o classe.o

subarquivo.o: subarquivo.cc classe.o
          $(CXX) $(FLAGS) -c main.cc subarquivo.o classe.o

classe.o: classe.cc
          $(CXX) $(FLAGS) -c classe.cc

clean:
          rm -rf *.o a.out

Assim, quando digitamos “make clean” na linha de comando, ele removerá todas os arquivos .o e o executável a.out que nós temos.

Conclusões

Os Makefiles são muito muito úteis ao tratar dos projetos. A primeira coisa que você deve fazer quando fazer um projeto é críar um makefile, ele torna sua vida muito mais fácil.

Referências

[1] Criando makefiles - Gazeta do linux
[2] Makefile Getting Started

quarta-feira, 18 de abril de 2007

Iniciando

Primeiramente é preciso escolher a plataforma de desenvolvimento, que passa pelas seguintes questões:
  • Sistema Operacional (Windows, Linux, MacOS, etc);
  • Ferramentas de desenvolvimento:
    • Linguagem (C, C++, Phyton, Pascal, Fortran, Java, etc);
    • IDE's (Eclipse, Anjuta, Dev-XXX, Visual-XXX(Microsoft), XXX-Builder(Borland), etc) ou;
    • Editores de texto (Kate, Xemacs, Gedit, Kwrite, Bloco de notas, etc)
    • Compiladores (gcc, g++, g77, etc)
    • Paradigma (Imperativa, Funcional, Declarativa)
    • Disciplina de programação (OO, Estruturada, etc)
    • Bibliotecas (runtime, glib, STL, etc)
Rodar exemplos é uma boa maneira de iniciar, pegar coisas prontas e tentar entender, ou olhar apostilas, tutoriais e documentações sobre os componentes escolhidos para a plataforma de desenvolvimento. Estudar também as opções que o compilador lhe ofereçe é uma boa, tais como: somente compilar, gerar executável, otimizar o código, depurar, etc.
Procurar dominar mais de uma tecnologia é sempre importante, para não ficar bitolado e saber se virar nas mais diferentes situações.