Você está na página 1de 18

PROPOSTA:

Convenções de Escrita de Código


Tecsys do Brasil Industrial Ltda.
Versão 1.0 – Março/2006

1
ÍNDICE

1. Introdução Pág. 3

2. Do Ambiente Pág. 4

2.1. Estrutura de Diretórios Pág. 4

2.2. Arquivo de Registro de Versões Pág. 4

2.3. Arquivos de Make e Projeto Pág. 5

2.4. Código de Inicialização Pág. 5

2.5. Stack e Heap Pág. 5

3. Módulos Pág. 7

3.1. Informações Gerais Pág. 7

3.2. Gabaritos Pág. 8

3.3. Nomes dos Módulos Pág. 10

4. Variáveis Pág. 11

4.1. Nomes Pág. 11

4.2. Variáveis Globais Pág. 11

4.3. Portabilidade Pág. 12

5. Funções Pág. 13

6. Rotinas de Tratamento de Interrupções (ISRs) Pág. 14

7. Comentários Pág. 15

8. Escrita de Código Pág. 16

8.1. Informações Gerais Pág. 16

8.2. Espaçamento e Indentação Pág. 16

8.3. Formatação de Código C Pág. 16

8.4. Formatação de Código Assembly Pág. 17

9. Glossário Pág. 18

2
1. INTRODUÇÃO

Este documento visa fornecer uma forma comum de escrita a fim de manter legível e gerenciável todo o
código produzido na empresa, e visa servir como orientação de utilização para os atuais e futuros programadores
que tiverem acesso a este código.
Todo código fonte escrito, seja em linguagem C, Assembly, Visual Basic ou qualquer outra linguagem de
programação que seja adotada no futuro, deve atender a dois propósitos básicos:

1. Deve funcionar;
2. Deve informar claramente a quem ler como funciona.

O primeiro propósito é atingido através de planejamento e aplicação de boas técnicas de programação,


tais como Programação Estruturada e Orientação a Objetos, e não é assunto deste documento.
O segundo propósito envolve convenções de codificação e técnicas de documentação, e é o assunto
sobre o qual este documento discorre.
As formas de escrever código são tantas quantas são as pessoas envolvidas em sua execução. Mesmo
quando somente um programador está envolvido na tarefa, com o passar do tempo ele tende a modificar seus
hábitos devido a novos métodos aprendidos e técnicas derivadas de sua própria experiência.
Quando o programador trabalha em equipe, as diferenças entre as formas de escrever podem dificultar o
desenvolvimento, visto que pode não haver clareza na interface entre os códigos desenvolvidos por cada um, e a
manutenção dos programas, uma vez que venha a ser futuramente necessário consertar e/ou adicionar recursos
aos produtos da empresa.
Portanto, não é suficiente que o código apenas funcione. É necessário que esteja devidamente
documentado a fim de que você, uma vez que já tenha esquecido dos detalhes do projeto, ou qualquer outro
programador que se encarregue da tarefa, possa ler e entender como o código funciona.
Em princípio, este documento não se propõe a ser um padrão que estabeleça uma forma de codificação
rígida, mas sim um guia para auxiliar à harmonização do código gerado pela equipe de programação.

3
2. DO AMBIENTE

2.1. Estrutura de Diretórios

Para simplificar a tarefa de fazer cópias de segurança dos códigos desenvolvidos e a possível utilização
de um programa gerenciador de versões (VCS – Version Control System), uma estrutura de diretórios deve ser
mantida com todo o código associado ao projeto. Esta estrutura deve, se possível, ser mantida em um servidor e ter
seu acesso liberado somente aos programadores envolvidos no projeto, para leitura, sendo que sua atualização, ou
escrita, deve ser permitida somente a um programador, normalmente o chefe ou responsável pelo projeto, que
atualizará o código fonte somente após revisá-lo e testá-lo.
Uma estrutura de diretórios sugerida pode ter a forma:

/projetos/nome_do_projeto

Dentro da pasta base, nomeada de acordo com o nome oficial ou formal do projeto, deverá haver:

/fontes Onde serão armazenados os códigos dos módulos do projeto, possivelmente em uma
subestrutura de diretórios.

/bin Onde serão armazenadas todas as ferramentas necessárias à geração dos arquivos
executáveis do projeto; note que nesta pasta estarão congeladas as versões das
ferramentas utilizadas com cada versão dos executáveis gerados com elas, pois é
impraticável retestar todas as versões do projeto com todas as versões futuras de
ferramentas que surgirem. Daqui a 5 ou 10 anos, se o produto ainda existir e for
necessária uma alteração, aquelas podem não ser mais encontradas.

/include Para os arquivos de inclusão com definições para os fontes, tais como arquivos .h de
linguagem C ou .inc de Assembly.

/objetos Opcional para arquivos objeto temporários e bibliotecas criadas durante a compilação
e linkedição do código.

/executaveis Onde serão armazenados os arquivos executáveis de todas as versões geradas para
este projeto.

Cada programador envolvido no projeto deverá ter uma cópia desta estrutura de diretórios em sua
máquina e ter condições de gerar os arquivos executáveis a fim de verificar e testar suas alterações. Caberá ao
responsável pelo projeto integrar as modificações à estrutura principal.

4
2.2. Arquivo de Registro de Versões

Cada projeto deverá possuir um arquivo especial que deverá conter o nome, data e código (part number)
de cada versão de arquivo executável criada. Este arquivo irá listar em ordem cronológica descendente (da mais
nova no topo até a mais antiga na base) todas as alterações feitas de versão para versão dos código fonte.
Um exemplo de tal arquivo está listado abaixo:

/*********************************************************************************
* Módulo de versões – Projeto AMOSTRA
*
* Copyright (C) 2006 Tecsys do Brasil Industrial Ltda.
* Todos os direitos reservados
*
* A informação contida aqui é confidencial e de propriedade
* da Tecsys do Brasil. O uso, cópia e divulgação são proibidos
* exceto com expressa autorização por escrito da Tecsys do Brasil.
*
* Versão Data Descrição/Autor
* ---------- -------- -----------------------
* 1.3 10/01/2006 ROM ID 45-130
* José da SIlva
* Modificado módulo KeyBoard para corrigir
* bug de reconhecimento do pressionamento
* conjunto das teclas UP e DOWN.
* 1.2 22/10/2005 ROM ID 45-120
* José da Silva
* Adicionada saída de informação de debug
* em PIO5 no módulo IO_Control conforme
* solicitado pelo cliente.
* 1.1 12/10/2005 ROM ID 45-110
* José da Silva
* Corrigida ISR do DAC2 para corrigir problema
* com interrupção reentrante.
* 1.0 02/10/2005 ROM ID 45-100
* José da Silva
* Versão inicial.
*********************************************************************************/
#undef SOFTWARE_VERSION
#define SOFTWARE_VERSION “Versao 1.30”

2.3. Arquivos de Make e Projeto

Todo executável deve ser gerado por um arquivo Makefile (em sistemas de linha de comando) ou pelo
arquivo equivalente de projeto (em ambientes integrados e/ou de interface gráfica). Este arquivo de dependências
deverá conter toda a informação necessária para automaticamente construir a imagem de execução do projeto,
incluindo comandos de compilação, assemblagem, linkedição, localização e quaisquer outros que sejam
necessários para a geração do arquivo executável final.
Preferencialmente, devem ser utilizadas duas versões do arquivo de dependências, uma para a geração
da imagem de execução final, com o máximo de otimizações oferecidas pelo compilador/assembler, e outra para
geração de uma imagem de depuração, com a adição de códigos de debug opcionais e provavelmente com as
otimizações inicialmente minimizadas ou desativadas.
De nenhuma forma deve haver mais de um comando destinado a construir a imagem de execução do
código.

2.4. Código de Inicialização

Quando uma linguagem de alto nível está sendo utilizada, em especial a linguagem C, normalmente é
necessária a adição de um código de inicialização de ambiente, tal como o cstartup.asm para alguns compiladores
C. O código de inicialização ou localização normalmente é fornecido junto com o ambiente de desenvolvimento, na
forma de código fonte e/ou bibliotecas.
O programador que trabalha com a linguagem deve conhecer o funcionamento do código de inicialização.
Caso necessite fazer alterações no mesmo, para atender a necessidades específicas de um projeto, deverá
documentar devidamente no arquivo fonte estas alterações, evitando excluir linhas de código que seriam retiradas
ou modificadas. Estas linhas deverão ser copiadas e comentadas, a fim de que possam ser restauradas para o
próximo projeto. Os comentários de alteração devem ser colocados no início do arquivo a fim de que qualquer
pessoa que o abra tenha a possibilidade de verificar que o mesmo tenha sido alterado de sua condição padrão.
Todo arquivo fonte fornecido pelo fabricante que tenha sido alterado, deve ter uma cópia salva junto aos
fontes do projeto, para utilização futura. Evite alterar arquivos que sejam constantemente utilizados pelo ambiente
de desenvolvimento.

5
2.5. Stack e Heap

Stack ou Pilha é a área de memória RAM utilizada para armazenamento temporário de informações
utilizadas durante a chamada de funções ou subrotinas. Quando uma instrução CALL ou JSR é executada, o
endereço da instrução chamadora é armazenado automaticamente na pilha para ser utilizado pela instrução de
retorno RET. A linguagem C utiliza a pilha como meio de passagem de parâmetros entre funções, para o código de
retorno da função chamada e para alocação de variáveis locais ou automáticas na entrada de funções.
A pilha é, portanto, um importante recurso que deve ser utilizado de forma cuidadosa. Programadores que
utilizam linguagens de alto nível normalmente não tem com o que se preocupar, a não ser que necessitem
modificar o código de inicialização da linguagem ou devam estabelecer o limite de utilização de pilha para o sistema
ou devam gerenciar a quantidade de pilha para criação de tarefas onde a quantidade desta deva ser especificada.
Programadores que utilizem microcontroladores com pequenas quantidades de memória RAM devem
calcular cuidadosamente a quantidade alocada para pilha ou para variáveis globais, pois como a alocação de
variáveis cresce da base para o topo da memória e a utilização da pilha cresce do topo para a base, a utilização
desordenada fará com que o encontro das duas seja a fonte de problemas misteriosos de alteração de valores de
variáveis e travamentos estranhos durante as fases de maior carga de processamento, devido à perda de
endereços de retorno.
Se você tiver que inicializar a pilha, sempre utilize endereços pares (even), ou seja, com o bit menos
significativo igual a 0. Resista à tentação de ganhar aquele último byte, o endereço 0xFFFF, pois a maioria dos
processadores utiliza quantidades de 16 bits para inserção e retirada de valores na pilha, e uma disposição ímpar
(odd) pode prejudicar o desempenho do sistema, especialmente aqueles com largura de barramento de dados de
16 bits.
Sempre considere que suas estimativas de utilização da pilha estarão incorretas e portanto, adote valores
conservativos. Uma forma interessante de testar a utilização da pilha é modificar o código de inicialização para, em
vez de preencher a área de memória da pilha com o valor 0x00, como é feito normalmente, preencher esta área
com um dos valores 0x55 ou 0xAA. Posteriormente, em qualquer simulador ou depurador (debugger) você poderá
acompanhar a ocupação da área de pilha simplesmente verificando a existência de valores 0x55 ou 0xAA ao final
da área de memória.
Programadores de linguagem Assembly devem evitar utilizar muitos níveis de chamada de funções, pois
a maioria das variáveis utilizadas serão globais, e não haverão mecanismos de alocação e liberação automáticos
de pilha, tais como os ajustes de entrada e de saída de funções adicionados automaticamente pelos compiladores.
Heap é uma palavra que não tem tradução ótima para o português, e é o nome dado à área de memória
alocável dinamicamente por programas em linguagem C. A maioria dos compiladores desta linguagem,
especialmente os voltados para microcontroladores, considera a memória RAM restante, após a alocação das
variáveis estáticas, globais e da pilha, como área de Heap. Blocos de memória são alocados através da função C
malloc(), que recebe a quantidade de bytes a alocar e retorna um ponteiro para o início do bloco alocado. Após sua
utilização, este blocos deverão ser liberados através da função free(). Quando estas funções são incluídas em seu
código, através de um dos arquivos de inclusão stdlib.h, heap.h, malloc.h, etc., também é adicionado o sistema de
gerenciamento, que tem como função mapear a utilização dos blocos de memória alocados e permitir a realocação
e liberação destes.
Entre os problemas que podem ser criados pela utilização do sistema malloc/free, estão a fragmentação
do Heap e o consumo de memória destinada ao gerenciamento de blocos. A fragmentação ocorre quando os
blocos de memória são alocados e liberados em diversos tamanhos, provocando o aparecimento de buracos de
tamanhos diversos no Heap. Uma nova solicitação pode ser rejeitada devido à quantidade solicitada, ainda que haja
memória livre suficiente para atender ao pedido. O gerenciamento de blocos, ainda que possa chegar a utilizar
apenas um byte por bloco de memória alocado, tende a sobrecarregar pequenos sistemas.
Se você pretende utilizar alocação dinâmica de memória em seu código, siga as sugestões a seguir:

. Leia o código das funções de alocação de memória disponíveis em seu ambiente de desenvolvimento
para conhecer como elas funcionam, pois em sistemas maiores, muitas vezes implementam esquemas de
desalocação dinâmicos, tais como coleta de lixo (garbage collection), que podem estar interferindo no desempenho
de seu sistema sem que você saiba;
. Sempre verifique os valores de retorno destas funções, a fim de que seu código possa ativar uma função
de erro ou exceção em caso de falha, e o problema possa ser comunicado quando de seu aparecimento;
. Nunca aloque ou libere blocos de memória dentro de uma rotina de tratamento de interrupção (ISR);
. Lembre-se de que em sistemas embarcados provavelmente seu código será executado quase sempre
de forma ininterrupta, e portanto os problemas de fragmentação do Heap serão mais visíveis e danosos do que em
programas de sistemas maiores, que normalmente são executados por pouco tempo e sob a proteção de um
Sistema Operacional.

6
3. MÓDULOS

3.1. Informações Gerais

Um Módulo é um arquivo de código fonte que contém uma ou mais funções ou rotinas relacionadas e as
definições de variáveis necessárias a estas.
As funções ou rotinas contidas em um módulo devem ser relacionadas entre sí, como, por exemplo, um
módulo de conversor A/D que reúne todas as funções de controle (drivers) do dispositivo ADC em um único
arquivo. Este tipo de agrupamento facilita a localização de seções de código relevantes e permite a utilização de
uma das boas técnicas de programação OOP, o encapsulamento.
Encapsulamento é o agrupamento de detalhes de operação de um módulo e as variáveis de que
necessita de forma que outros módulos não tenham acesso a estes detalhes. A comunicação entre os módulos
deve ser feita através de interfaces bem definidas e documentadas, o que isola o código chamador e o código
chamado, podendo o desenvolvimento de cada um dos dois ser feito separadamente. A técnica de encapsulamento
desencoraja a utilização de variáveis globais e os problemas associados ao acesso concorrente destas áreas de
memória.
Módulos tendem a crescer descontroladamente quando não forem bem planejados. Idealmente, os
módulos devem ser mantidos abaixo de 1000 linhas para que a clareza dos mesmos seja mantida e ferramentas
tais como depuradores e compiladores possam funcionar adequadamente.

7
3.2. Gabaritos

Para encorajar uma aparência e disposição de módulos semelhante, gabaritos ou templates podem ser
utilizados para geração de novos módulos. Estes arquivos devem ser armazenados no diretório /fontes e salvos
junto com o código do projeto. Um exemplo de gabarito para linguagem C é dado abaixo:

/*********************************************************************************
* Projeto nome_do_projeto
*
* Arquivo: Nome_do_arquivo.ext
* Descrição:Descrição_suscinta_do_módulo
* Autor: Nome_do_autor
* Alterações: Versão Data Autor Alteração
* --------- ----------- ----------- ---------------
* 0.0 DD/MM/AAAA iniciais Descrição_da_alteração
*
* Copyright (C) 2006 Tecsys do Brasil Industrial Ltda.
* Todos os direitos reservados
*
* A informação contida aqui é confidencial e de propriedade
* da Tecsys do Brasil. O uso, cópia e divulgação são proibidos
* exceto com expressa autorização por escrito da Tecsys do Brasil.
*
*------------------------------------------------------------------------------
* Descrição_detalhada_do_módulo
*
*********************************************************************************/

/*********************************************************************************
* Inclusões
*********************************************************************************/
/* Adicione aqui os arquivos de inclusões */

/*********************************************************************************
* Definições locais
*********************************************************************************/
/* Adicione aqui os #defines */

/*********************************************************************************
* Protótipos
*********************************************************************************/
/* Adicione aqui os protótipos das funções do módulo */

/*********************************************************************************
* Definições de funções
*********************************************************************************/
/* Adicione aqui os códigos para as funções do módulo */

/*********************************************************************************
* Função: TIPO Nome ( TIPO parâm_1, TIPO parâm_2 )
* Descrição:Descrição_da_função
* Criação: DD/MM/AAAA
* Entrada: parâm_1 Descrição_parâm_1
* parãm_2 Descrição_parâm_2
* Saída: Efeitos_sobre_parâmetros_e_variáveis_globais
* Retorna: Listagem_de_códigos_de_retorno_ou_efeitos
* Notas: Alterações_e_outros
*********************************************************************************/

/***** Fim de arquivo *********************************************************/

Note que o cabeçalho de descrição de cada função do módulo também deverá estar definido no gabarito.
O indicador de final de arquivo é útil para verificação da integridade do mesmo, pois caso este tenha sido truncado
ao final ou blocos de armazenamento do arquivo tenham sido perdidos pelo sistema operacional, o final do arquivo
é o ponto mais provável a ser atingido. Lembre-se sempre de inserir uma mudança de linha ao final do indicador,
pois a maioria dos compiladores C geram erros de compilação se não há uma linha vazia ao final do arquivo.
O gabarito para arquivos Assembly pode ter a estrutura sugerida abaixo:

8
;*********************************************************************************
; Projeto nome_do_projeto
;
; Arquivo: Nome_do_arquivo.ext
; Descrição: Descrição_suscinta_do_módulo
; Autor: Nome_do_autor
; Alterações: Versão Data Autor Alteração
; --------- ----------- ----------- ---------------
; 0.0 DD/MM/AAAA iniciais Descrição_da_alteração
;
; Copyright (C) 2006 Tecsys do Brasil Industrial Ltda.
; Todos os direitos reservados
;
; A informação contida aqui é confidencial e de propriedade
; da Tecsys do Brasil. O uso, cópia e divulgação são proibidos
; exceto com expressa autorização por escrito da Tecsys do Brasil.
;
;------------------------------------------------------------------------------
; Descrição_detalhada_do_módulo
;
;*********************************************************************************

;*********************************************************************************
; Inclusões
;*********************************************************************************
; Adicione aqui a lista de arquivos de inclusão (.inc ou .def)

;*********************************************************************************
; Definições locais
;*********************************************************************************
; Adicione aqui os comandos EQU e DB/DS

;*********************************************************************************
; Definições de rotinas
;*********************************************************************************
; Adicione aqui os códigos para as rotinas do módulo

;*********************************************************************************
; Rotina: Nome_da_rotina
; Descrição: Descrição_da_rotina
; Criação: DD/MM/AAAA
; Entrada: parâm_1 Descrição_parâm_1
; parãm_2 Descrição_parâm_2
; Saída: Efeitos_sobre_parâmetros_e_variáveis_globais
; Retorna: Listagem_de_códigos_de_retorno_ou_efeitos
; Notas: Alterações_e_outros
;*********************************************************************************

;*********************************************************************************
; Vetores de interrupção
;*********************************************************************************
; Adicione aqui os endereços das rotinas de tratamento de interrupções

;***** Fim de arquivo *********************************************************

O indicador de linha de comentário mais comum entre os assemblers é o ponto-e-vírgula (;), mas o
asterisco (*) é também bastante comum. Substitua o caracter inicial dos cabeçalhos acima pelo caracter de
comentário utilizado por sua ferramenta.

9
3.3. Nomes dos Módulos

Nunca inclua o nome do projeto ou acrônimo como parte de cada nome de módulo. Um módulo utilizado
em um projeto pode ser reutilizado em outro, e sua nomenclatura será estranha ao novo projeto.
Grandes projetos podem gerar dezenas de módulos, e buscar o ponto de início do programa por vários
arquivos pode ser uma tarefa frustrante. O ponto de início, em linguagem C a função main(), deve ser colocado em
um arquivo main.c ou main.asm, a fim de facilitar sua localização.
Nomes de arquivos devem ser escritos em caixa baixa a fim de facilitar a portabilidade entre sistemas
operacionais. Hoje em dia a limitação de nome de arquivo e extensão da forma 8.3 utilizada pelo MS-DOS já não é
um empecilho, mas utilizar nomes de arquivo demasiado grandes pode dificultar seu trabalho. O nome do arquivo
deve ter o tamanho suficiente para descrever o módulo que contém.
As extensões de arquivos devem ser padronizadas a fim de não dificultar o trabalho das ferramentas de
desenvolvimento. As extensões deverão ser:

Arquivos fontes em linguagem C: arquivo.c


Arquivo de inclusão em linguagem C: arquivo.h
Arquivos fontes em linguagem Assembly: arquivo.asm
Arquivos de inclusão de linguagem Assembly: arquivo.inc
Bibliotecas arquivo.lib
Arquivos de comandos do Shell (Scripts): arquivo.bat
Arquivos intermediários de código objeto: arquivo.obj
Arquivo de descrição do conteúdo de diretório: LEIAME
Arquivo de regras de construção: projeto.mak

10
4. VARIÁVEIS

4.1. Nomes

Independentemente da linguagem utilizada, use nomes longos para clarificar o significado da variável.
Qualquer compilador atual permite o uso de nomes de ao menos 32 caracteres.
Separe as palavras que constituem o nome com o caracter de sublinhado, ao invés de utilizar letras
maiúsculas como separadores. Compare os nomes a seguir: Contador_de_Iteracoes e ContadorDeIteracoes.
Nomes de variáveis e funções são definidos com as primeiras palavras descrevendo idéias mais amplas e
as últimas palavras se aproximando da idéia específica. Por exemplo:

Universo_Galaxia_Sistema_Planeta.

Considere os nomes a seguir:

Timer_0_Overflow
Timer_0_Capture

Esta convenção rapidamente aproxima variáveis a determinados segmentos do programa. Nunca assuma
que um verbo deve estar no início, como normalmente se vê em nomes de funções.
Open_Serial_Port e Close_Serial_Port não agrupam as funções tão bem quanto Serial_Port_Open e
Serial_Port_Close.
Acrônimos e abreviações não são permitidos como partes de nomes de variáveis, a menos que:

1. Estejam definidos em uma Tabela de Abreviações permitidas para o projeto e que será armazenada no
arquivo de Registro de Versões;
2. Seja uma convenção aceita pela indústria, tal como LCD, LED e DSP.

Um exemplo de Tabela de Abreviações pode ser:

/*********************************************************************************
* Tabela de Abreviações
* Abreviações aceitas em nomes de variáveis e funções
*-----------------------------------------------------------------------------
* Calc = Cálculo
* Cnt = Contador
* Pos = Posição
* Ptr = Ponteiro
* Tot = Total
* Val = Valor
*********************************************************************************/

O padrão ANSI C restringe o use de nomes que iniciam com um sublinhado (_) e uma letra maiúscula ou
outro sublinhado ( _[A-Z_][0-9 A-Z a-z_] ). Muitos fabricantes também utilizam palavras iniciadas com sublinhado
para conversão de variáveis C para Assembly. Para evitar confusão, nunca nomeie uma variável ou função com
uma palavra iniciada com sublinhado.
Os nomes a seguir também são reservados pela ANSI para expansão futura da linguagem C:

E[0-9 A-Z][0-9 A-Z a-z]* valores de errno


is[a-z][0-9 A-Z a-z]* Classificação de caracteres
to[a-z][0-9 A-Z a-z]* Manipulação de caracteres
LC_[0-9 A-Z a-z_]* Configuração de local (Locale)
SIG[_A-Z][0-9 A-Z a-z_]* Sinais
str[a-z][0-9 A-Z a-z_]* Manipulação de cadeias de caracteres (strings)
mem[a-z][0-9 A-Z a-z_]* Manipulação de memória
wcs[a-z][0-9 A-Z a-z_]* Manipulação de caracteres largos (wide character)

4.2. Variáveis Globais

É comum em programas C e especialmente Assembly terem um grande módulo com todas as definições
de variáveis. Ainda que pareça organizado concentrar todas as variáveis em um único lugar, um grande problema
criado é a transformação destas variáveis para um escopo de utilização global. Variáveis globais são responsáveis
por muito código não-depurável e problemas de reentrância de funções.
Código de execução em tempo real pode ocasionalmente requerir algumas, poucas, variáveis globais
para garantir um tempo de resposta razoável para eventos externos. Uma regra que pode ser utilizada é: Toda
variável global deve ser aprovada pelo responsável pelo projeto.
Quando variáveis globais devam ser utilizadas, concentre-as em um único módulo, para que possam ser
facilmente identificadas. Este módulo deve ser identificado como globais.c ou globais.asm.

11
4.3. Portabilidade

A portabilidade da linguagem C permite que programas escritos em ANSI C possam ser recompilados
nas mais diversas plataformas, de um microcontrolador da família HC08, de 8 bits, até um processador Athlon de
64 bits. Um dos problemas originados desta característica é a diferença no tamanho dos tipos de variáveis de uma
e outra plataforma. Apesar de que dificilmente um programa escrito para o MC68HC908QT1 seja recompilado para
um Athlon64, se o programador utiliza estas duas plataformas ele poderá vir a confundir os tamanhos dos tipos de
cada uma, ao se mover de uma para outro, e tornar este equívoco uma fonte de problemas para seu código.
Segue abaixo uma lista de exemplos dos tamanhos dos tipos em C para algumas das plataformas
utilizadas na empresa:

Tipo Sti5518 MC68HC908QT1 IBM-PC

char 8 bits 8 bits 8 bits


short int 16 bits 16 bits 16 bits
int 32 bits 16 bits 16 bits
long 32 bits 32 bits 32/64 bits

Pode-se verificar que as principais diferenças residem no tamanho das variáveis int e long, mas se um
programador retira um código em C antigo da Internet, especialmente de um computador VAX, pode ter que lidar
com variáveis char de 18 bits.
Para evitar estes problemas de dependência de plataforma, pode-se utilizar um recurso muito útil da
linguagem C, o comando typedef. typedef cria novos tipos partindo da redefinição de tipos antigos e mistos. O
problema acima pode ser contornado através da criação de um arquivo de inclusão dependente de plataforma que
defina os tipos:

Sinalizado Não-Sinalizado
8 bits: int8_t uint8_t
16 bits: int16_t uint16_t
32 bits: int32_t uint32_t
64 bits: int64_t uint64_t

Outro detalhe importante em questões de portabilidade de código é a ordem de disposição de bytes e


palavras mais e menos significativos na memória do processador. Nunca se deve assumir que o endereço do byte
menos significativo de uma palavra ou palavra longa é o endereço da palavra ou da palavra longa, pois isto só é
válido em máquinas little-endian.

12
5. FUNÇÕES

Qualquer que seja a sua linguagem de programação, mantenha as funções pequenas. O tamanho ideal é
de menos que uma página; não deve haver situação em que uma função exceda a duas páginas de apresentação,
impressa ou na tela do terminal de trabalho. Funções grandes devem ser quebradas em funções menores.
A única exceção a esta regra é o raro caso onde requisitos de funcionamento de tempo real (ou
limitações de área de pilha) obriguem a construção de funções com longas seqüências de código linear. O
responsável pelo projeto deverá aprovar tal código, mas uma opção melhor deverá sempre ser procurada.
Declare explicitamente cada parâmetro passado para cada função, e claramente documente a
necessidade e o significado de cada parâmetro no cabeçalho de descrição da função.
Toda função deve ter seu protótipo definido, seja no corpo do módulo, seja em um arquivo de inclusão do
módulo, a ser utilizado por outros módulos que utilizem as funções deste. Protótipos auxiliam o compilador a
localizar erros de definição de tipo e quantidade de parâmetros.
Em geral, os nomes de funções devem seguir o protocolo de criação de nomes para variáveis.

13
6. ROTINAS DE TRATAMENTO DE INTERRUPÇÕES (ISRs)

Ainda que sejam uma pequena parte do código, as ISRs são geralmente os piores trechos de código para
projetar e depurar. ISRs apropriadas, todavia, requerem um hardware bem desenhado. Algumas vezes é tentador
deixar de utilizar algumas portas e CIs, deixando um dispositivo externo ativar a linha de interrupção somente por
alguns microssegundos, mas esta é uma condição inaceitável. Cada interrupção deve ser sustentada até que seja
aceita e atendida pelo processador.
Interrupções não mascaráveis (NMIs) somente devem ser utilizadas para eventos catastróficos, tal como
uma queda de energia iminente. Muitas ferramentas não podem depurar devidamente código que trata uma NMI, e
estas garantidamente quebram código não-reentrante.
Se possível, reserve no projeto algumas linhas de Entrada e Saída (I/O), pois estas serão extremamente
úteis para medir e/ou sinalizar performance e execução das ISRs.
Mantenha ISRs curtas. Rotinas longas e lentas são garantias de desastres e muitos problemas de
desempenho do programa. Lembre-se que as características de longas e lentas podem não estar juntas, pois uma
ISR de cinco linhas que contenha um laço de execução (loop) pode dar tanto problema quanto uma ISR sem laços
de repetição de 500 linhas. Quando uma ISR cresce demais ou se torna lenta, faça com que ela sinalize o trabalho
necessário para outra tarefa e saia. Se as ISRs estão se tornando grandes e complexas, é uma indicação de que
seu projeto precisa de um RTOS.
Crie prazos de desenvolvimento para cada ISR importante. Antes de escrever o código da rotina, entenda
quanto tempo está disponível para seu processamento. Baseie seu código nisto e então meça a performance
resultante da ISR para ver se ela atende aos requisitos de seu sistema. Desde que toda interrupção compete pelos
recursos da CPU, aquela ISR lenta que funciona pode ser tão ruim quanto aquela com código totalmente
corrompido.
Em processadores com tabela de vetores de interrupções, preencha todas as entradas disponíveis.
Aponte aquelas entradas não utilizadas por seu sistema para uma rotina de tratamento de erros, pois assim você
conseguirá encontrar problemas com vetores preenchidos incorretamente.
Ainda que código não-reentrante seja sempre perigoso em um sistema de tempo real, é geralmente
inevitável em uma ISR, tais como as que atendem a interfaces de hardware. Insira o código não-reentrante no início
da ISR para que seja executado tão rápido quanto possível, a fim de que você possa novamente habilitar as
interrupções. Lembre-se de que enquanto as interrupções estiverem desligadas, o sistema deixa de responder a
eventos externos.

14
7. COMENTÁRIOS

O código implementa um algoritmo; os comentários comunicam a operação do código para você e para
outros. Comentários adequados permitem que você entenda a operação do sistema sem ter que ler o próprio
código.
Escreva comentário em Português claro, tente não utilizar excesso de anglicismos, ainda que devamos
reconhecer que nossa área de trabalho está repleta deles. Utilize somente os que não tem uma tradução clara para
o português, tal como a palavra Heap. A área de comentários não é acessível ao compilador ou assembler, e a
maioria dos editores reconhece a nossa página de código, portanto utilize acentos ao escrever.
Evite comentários demasiado grandes, mas escreva o quanto seja suficiente para que este esteja
completo de forma a mais concisa possível.
Evite parágrafos longos e utilize sentenças simples: nome, verbo, objeto.
Use voz ativa: “Motor_Liga atua o relé de indução após uma pausa de 4 segundos.”
Seja completo. Bons comentários capturam tudo o que é importante sobre o problema em mãos.
Utilize corretamente o tipo de caixa, pois texto todo em maiúsculas ou todo em minúsculas se torna mais
difícil de ler e faz com que o autor pareça não ter recebido educação básica.
Em linguagem C, faça comentários em nível de bloco e quando necessário para esclarecer uma linha.
Não se sinta compelido a comentar cada linha. É muito mais natural comentar um grupo de linhas que trabalham
juntas para realizar uma macro função. Entretanto, nunca assuma que nomes de variáveis longos criam código
“autodocumentado”. Deve ser possível deduzir a operação do sistema somente lendo os comentários.
Explique o significado e função de cada declaração de variável, cada uma. Explique o valor de retorno se
houver. Nomes longos de variáveis são somente um auxílio ao entendimento; acompanhe o nome descritivo com
uma descrição significativa em prosa.
Explique os parâmetros durante a definição de função, tal como abaixo:

TIPO nome_da_função ( TIPO parâmetro1, /* Comentário */


TIPO parâmetro2 /* Comentário */
...

Comente blocos de linguagem Assembly, e qualquer linha que não tenha um funcionamento claro. Os
piores comentários são aqueles que afirmam:

mov A, B ; Mova B para A

Acrônimos e abreviações não são permitidos a menos que estejam definidos na Tabela de Abreviações
armazenada no arquivo de Registro de Versões. Enquanto “DSP” pode significar “Display” para você, para mim
significa “Digital Signal Processor”. Nosso objetivo é a clareza.
Ainda que seja útil demarcar as áreas de comentários com cadeias de asteriscos, nunca os utilize no lado
direito de um bloco de comentários. É muito trabalhoso e consome muito tempo conseguir o espaçamento correto
durante a digitação e se depois o comentário precisar ser alterado. Em outras palavras, não é permitido:

/*********************************************************************************
* Este comentário incorretamente utiliza caracteres à direita *
* para destacar o comentário *
*********************************************************************************/

A forma correta seria:

/*********************************************************************************
* Este comentário utiliza caracteres corretamente
* para destacar o comentário
*********************************************************************************/

15
8. ESCRITA DE CÓDIGO

8.1. Informações Gerais

Nenhuma linha deve ultrapassar 80 caracteres, a fim de que o código possa seja lido nos mais diversos
tipos de terminais e telas de visualização, bem como ser impresso sem deslocamentos e quebras de linha.
Não utilize caminhos absolutos quando incluindo arquivos. Caminhos relativos ou definições de caminhos
de procura devem ser definidos pelo ambiente de desenvolvimento a fim de que os arquivos sejam encontrados nos
lugares corretos.
Nunca use “números mágicos” para qualquer codificação. Ao invés, primeiro entenda de onde o número
surgiu, então o defina em uma constante, e por fim documente o seu entendimento deste número na declaração da
constante.

8.2. Espaçamento e Indentação

Coloque um espaço após cada palavra chave, a menos que um ponto-e-vírgula seja o próximo caracter,
mas nunca entre nomes de funções e a lista de argumentos.
Coloque um espaço após cada vírgula em lista de argumentos e após os ponto-e-vírgulas que separam
as expressões em um comando for.
Ponha um espaço antes e depois de cada operador binário (como +, -, *, etc.). Nunca insira um espaço
entre um operador unário e seu operando (por exemplo i--).
Ponha um espaço antes e depois operadores de ponteiros (*, &) em declarações. Preceda operadores de
ponteiros com um espaço, mas não coloque um depois, em expressões.
Indente código C em incrementos de dois espaços, ou seja, cada nível de indentação será de dois,
quatro, seis, etc. espaços.

8.3. Formatação de Código C

Nunca aninhe comandos if por mais de três níveis, pois acima disto o código torna-se incompreensível. É
melhor chamar uma função ou mesmo substituir grupos complexos de ifs por uma estrutura switch.
Coloque chaves de maneira que a chave de abertura seja a última coisa na linha, e posicione a chave de
fechamento, tal como:

if (resultado > teste) {


alguma coisa a fazer
}

Note que a chave de fechamento está em sua própria linha, exceto quando é seguida por uma
continuação do mesmo comando, tal com:

do {
corpo do loop
} while (condição);

Quando um comando if-else for aninhado em outro comando if, sempre ponha chaves em volta do if-else
para tornar claro o escopo do primeiro if.
Quando dividindo uma linha de código, indente a segunda linha da forma a seguir:

função (float arg1, int arg2, long arg3,


int arg4)

ou

if (nome_longo_de_variavel && constante_parecida == 2


&& outra_condicao)

Ainda quanto a if e testes condicionais, quando houver um teste com uma constante, em vez da forma
comum:

if (teste == CONSTANTE)
bloco condicional

digite

if (CONSTANTE == teste)
bloco condicional

Esta é uma forma interessante de evitar o famoso erro de digitação de um único sinal de igual (=), de
inserção de valores, em lugar do suplo igual (==), de teste de igualdade. O compilador encontrará a tentativa de
inserir um valor em uma constante e emitirá um erro, ao invés de silenciosamente aceitar a condição com um único

16
sinal de igual, incorreta, mas legal.
Abuse do uso de parênteses. Nunca deixe o compilador decidir sobre a precedência de execução, declare
explicitamente a precedência através de parênteses.
Nunca faça conversões de tipo dentro de comando if. Por exemplo, não escreva:

if ((foo = (char *) malloc (sizeof *foo)) == 0)


fatal (“memoria virtual exaurida”);

ao contrário, escreva:

foo = (char *) malloc (sizeof *foo);


if (foo == 0)
fatal (“memoria virtual exaurida”);

Se você utilizar #ifdefs para selecionar entre um grupo de opções de configuração, sempre adicione um
#else final contendo uma diretiva #error de forma que o compilador irá gerar uma mensagem de erro se nenhuma
das opções for definida.

#ifdef sun
#define USE_MOTIF
#elif hpux
#define USE_OPENLOOK
#else
#error Tipo de maquina desconhecida
#endif

8.4. Formatação de Código Assembly

Pontos de parada em linguagem devem ser:

. Primeiro TAB: Coluna 8


. Segundo TAB: Coluna 16
. Terceiro TAB: Coluna 32

Note que estes são todos incrementos de 8, para editores que não suportem configurações explícitas de
tabulação. Um grande espaço – 16 colunas – está entre os operandos e os comentários.
Posicione os labels em linhas próprias, tal como:

label:
mov r1, r2 ; r1=aponta para a porta de I/O

Precede e complete blocos de comentários com linha contendo somente um ponto-e-vírgula:

;
; Bloco de comentário que mostra como comentários
; se destacam do código quando cercados por linhas
; em “branco”.
;

Nunca avance um comentário sobre a linha de código seguinte, que não tenha a ver com ele:

mov r1, r2 ; Agora setamos r1 para o valor


add r3, [dado] ; que lemos do ADC

Ao invés, use ou um bloco de comentários, ou uma linha sem uma instrução, tal como:

mov r1, r2 ; Agora setamos r1 para o valor


; que lemos do ADC
add r3, [dado]

Tenha cuidado com macros. Ainda que úteis, macros podem rapidamente obscurecer o significado. Se
utilizar, nomeie as macros com nomes bastante significativos.

17
9. GLOSSÁRIO

ADC (Analogue to Digital Converter) Conversor Analógico-Digital


DAC (Digital to Analogue Converter) Conversor Digital-Analógico
DSP (Digital Signal Processor) Processador Digital de Sinais
I/O (Input/Output) Entrada/Saída
ISR (Interrupt Service Routine) Rotina de Tratamento de Interrupção
LCD (Liquid Cristal Display) Mostrador de Cristal Líquido
NMI (Non Masqued Interrupt) Interrupção Não Mascarada
OOP (Object Oriented Programming) Programação Orientada a Objetos
RAM (Random Access Memory) Memória de Acesso Aleatório
ROM (Read Only Memory) Memória Somente de Leitura
RTOS (Real-Time Operating System) Sistema Operacional de Tempo Real
VCS (Version Control System) Sistema de Controle de Versões

18

Você também pode gostar