linguagem c disciplina: aam profa. ana watanabe 27/02/13
TRANSCRIPT
Linguagem C
Disciplina: AAM
Profa. Ana Watanabe
27/02/13
• “Porque o SENHOR dá a sabedoria; da sua boca é que vem o conhecimento e o entendimento.” Provérbios 2:6
Linguagem C
• Objetivo da aula:
• Revisão da Linguagem;• Otimização de programa em C para Sistemas
Embarcados.• Exercício
Revisão da Linguagem C
• Surgiu nos anos 70 de uma linguagem chamada B. criada por Dennis Ritchie.
• Qualquer programa C ANSI pode ser compilado em qualquer compilador C ANSI não importando a máquina na qual o programa vá ser executado.
• Portanto => portabilidade, a escolha acaba recaindo sobre a linguagem C.
Revisão da Linguagem C
• Esta linguagem foi criada, influenciada e testada em campo por programadores. Ela oferece ao programador exatamente o que ele quer: poucas restrições, código rápido e eficiência. Por isso ela é a linguagem mais popular entre os programadores profissionais altamente qualificados.
Revisão da Linguagem C
• Programação estruturada: A linguagem C é uma linguagem estruturada em bloco simples => habilidade de uma linguagem tem de seccionar e esconder do resto do programa todas as instruções necessárias para a realização de uma determinada tarefa.
Revisão da Linguagem C
• Declaração de variáveis: Variáveis devem ser declaradas antes de serem usadas, permitindo assim, que o compilador saiba de antemão
• informações como tipo e espaço gasto• em memória podendo fazer checagem• durante o processo de compilação.
Revisão da Linguagem C
• Funções: Blocos de Código: Conjunto de comandos que executa uma determinada operação no programa. Normalmente é útil quando se necessita repetir um mesmo trecho de código várias vezes em um programa.
Revisão da Linguagem C
• Sensitive case: Significa que na linguagem C as letras maiúsculas e minúsculas são tratadas como caracteres diferenciados.
• Ex.: Podemos declarar uma variável For, apesar de haver uma palavra reservada for, mas isto não é uma coisa recomendável de se fazer pois pode gerar confusão!!
Revisão da Linguagem C
• Comentários:
• /* comentário de uma ou várias linhas. O padrão não permite comentários aninhados
(um dentro do outro), mas alguns compiladores os aceitam.
*/• // comentário de uma linha!!!!
Revisão da Linguagem C
Palavras reservadas:
Revisão da Linguagem C
• ESTRUTURA BÁSICA DE UM PROGRAMA:
1) INCLUSÃO DE ARQUIVOS EXTERNOS2) DECLARAÇÃO DE VARIÁVEIS GLOBAIS3) DECLARAÇÃO DE PROTÓTIPOS DE FUNÇÕES4) FUNÇÃO PRINCIPAL (main) 5) FUNÇÕES
Revisão da Linguagem C
• Protótipos de Funções:• Normalmente escrevemos as funções antes de
escrevermos a função main().• Isto é, as funções estão fisicamente antes da função
main().• Isto é feito por uma razão. Imagine-se na “pele” do
compilador. Se você fosse compilar a função main(), onde são chamadas as funções, você teria que saber com antecedência quais são os tipos de retorno e quais são os parâmetros das funções para que você pudesse gerar o código corretamente.
Revisão da Linguagem C
• Protótipos de Funções:• Foi por isto que as funções foram colocadas
antes da função main(): quando o compilador chegasse à função main() ele já teria compilado as funções e já saberia seus formatos.
Revisão da Linguagem C
• Protótipos de Funções:• Muitas vezes teremos o nosso programa
espalhado por vários arquivos. Ou seja, estaremos chamando funções em um arquivo que serão compiladas em outro arquivo. Como manter a coerência?
Revisão da Linguagem C
• Protótipos de Funções:• A solução são os protótipos de funções. Protótipos
são nada mais, nada menos, que declarações de funções. Isto é, você declara uma função que irá usar. O compilador toma então conhecimento do formato daquela função antes de compilá-la. O código correto será então gerado. Um protótipo tem o seguinte formato:
• tipo_de_retorno nome_da_função (declaração_de_parâmetros);
Revisão da Linguagem C
• tipo_de_retorno nome_da_função (declaração_de_parâmetros);
• onde o tipo_de_retorno, o nome_da_função e a declaração_de_parâmetros são os mesmos que você pretende usar quando realmente escrever a função. Repare que os protótipos têm uma nítida semelhança com as declarações de variáveis.
Revisão da Linguagem C#include <stdio.h>float Square (float a); // prototipoint main (){float num;num=Square(num);return 0;}float Square (float a){return (a*a);}
Revisão da Linguagem C
Tipos de Dados:• char ( sinalizados –positivo ou negativo) ou não sinalizado – positivo)• inteiro ( sinalizados –positivo ou negativo) ou não sinalizado – positivo)• real ( valores inteiros ou fracionários – float ou double)• nulo ( void – tipo vazio, ou um "tipo sem (tipo". Não retornam e/ou recebem valores – parâmetros)
Revisão da Linguagem C
Modificadores de Tipos de dados:
• short (reduz a faixa de representação do tipo)• long (ampliar a faixa de representação do tipo)• signed (para especificar a representação de valores sinalizados – compl. de dois)• unsigned (para especificar a representação de valores não sinalizados)
OTIMIZAÇÃO DE PROGRAMA EM C PARA SISTEMAS EMBARCADOS
http://sergioprado.org/otimizacao-de-codigo-em-linguagem-c-parte-1
Escrever código para estes dispositivos requer atenção especial quanto a utilização e gerenciamento eficiente dos recursos disponíveis. Por que?
OTIMIZAÇÃO DE PROGRAMA EM C PARA SISTEMAS EMBARCADOS
• Sistemas embarcados têm como uma de suas principais características a limitação de recursos computacionais (quantidade de memória, capacidade de processamento e dispositivos de I/O).
• Aplicações bem específicas => projetadas na medida para cumprir sua função.
OTIMIZAÇÃO DE PROGRAMA EM C PARA SISTEMAS EMBARCADOS
Vantagens da otimização:
• Diminuir custos do projeto;• Tempo de desenvolvimento;• Tamanho do dispositivo;• Consumo elétrico.
OTIMIZAÇÃO DE PROGRAMA EM C PARA SISTEMAS EMBARCADOS
Vantagens da otimização:
• Diminuir custos do projeto;• Tempo de desenvolvimento;• Tamanho do dispositivo;• Consumo elétrico.
OTIMIZAÇÃO DE PROGRAMA EM C PARA SISTEMAS EMBARCADOS
• O compilador C é a ferramenta que irá transformar seus algoritmos (código-fonte C), na sua aplicação.
• O compilador realiza uma série de transformações no código-fonte para gerar o melhor código possível, como por exemplo salvar variáveis em registradores ao invés de usar a memória para melhorar o tempo de acesso (otimização de processamento) ou remover código inútil do programa (otimização de espaço).
OTIMIZAÇÃO DE PROGRAMA EM C PARA SISTEMAS EMBARCADOS
• Em um compilador C moderno, o processo de compilação envolve basicamente os seis passos, na ordem apresentada:
• 1. Pré-processamento: Conversão do código-fonte em uma linguagem intermediária. É aqui que as diretivas de compilação são processadas e a sintaxe do código é verificada.
OTIMIZAÇÃO DE PROGRAMA EM C PARA SISTEMAS EMBARCADOS
• 2. Otimização de alto nível: É nesta etapa que o compilador realiza a primeira otimização do código, em cima do código-fonte da aplicação. Veremos mais adiante algumas das técnicas para auxiliar o compilador neste trabalho de otimização.
OTIMIZAÇÃO DE PROGRAMA EM C PARA SISTEMAS EMBARCADOS
• 3. Geração do código: Geração do código de máquina para a arquitetura-alvo. Nesta fase o compilador faz todas as conversões necessárias para a arquitetura em questão. Expressões aritméticas de 32 bits em processadores de 8 bits são convertidas em expressões aritméticas de 8 bits, por exemplo.
OTIMIZAÇÃO DE PROGRAMA EM C PARA SISTEMAS EMBARCADOS
• 4. Otimização de baixo nível: Nesta fase a otimização é realizada em cima do código-objeto gerado na fase anterior, como por exemplo removendo instruções não usadas ou redundantes.
OTIMIZAÇÃO DE PROGRAMA EM C PARA SISTEMAS EMBARCADOS
• 5. Assembler: Nesta etapa o compilador gera o arquivo-objeto correspondente ao arquivo-fonte C compilado.
OTIMIZAÇÃO DE PROGRAMA EM C PARA SISTEMAS EMBARCADOS
• 6. Linkagem: Por último, o compilador faz a linkagem de todos os arquivos-objeto em um único arquivo binário para ser carregado na memória do dispositivo.
OTIMIZAÇÃO DE PROGRAMA EM C PARA SISTEMAS EMBARCADOS
• Percebe-se que, dentre as seis etapas no processo de compilação descritas, quando pensamos em otimização de código, deve -se focar nas etapas 2 (Otimização de alto nível) e 4 (Otimização de baixo nível).
OTIMIZAÇÃO DE PROGRAMA EM C PARA SISTEMAS EMBARCADOS
Técnicas que podem auxiliar e instruir o compilador na tarefa de otimizar o código gerado:
OTIMIZAÇÃO DE PROGRAMA EM C PARA SISTEMAS EMBARCADOS
A) O tempo de acesso aos registradores da CPU é normalmente muito mais rápido do que o tempo de acesso à memória de dados, e o processador possui melhor performance quando realiza cálculos utilizando registradores ao invés de memória.
• Porisso, o compilador procura alocar variáveis locais e parâmetros para funções em registradores para melhorar a performance do sistema.
OTIMIZAÇÃO DE PROGRAMA EM C PARA SISTEMAS EMBARCADOS
• O compilador precisa decidir quais variáveis irão ser acessadas através de registradores e quais deverão ser mantidas em memória.
• Pode-se instruir o compilador através da palavra-chave register, conforme mostra a listagem:
int exp(register int base, register int expoente) { register int resultado = 1; for (; expoente; expoente--) resultado *= base; return(resultado); }
OTIMIZAÇÃO DE PROGRAMA EM C PARA SISTEMAS EMBARCADOS
• O compilador precisa decidir quais variáveis irão ser acessadas através de registradores e quais deverão ser mantidas em memória.
• Pode-se instruir o compilador através da palavra-chave register, conforme mostra a listagem:
int exp(register int base, register int expoente) { register int resultado = 1; for (; expoente; expoente--) resultado *= base; return(resultado); }
OTIMIZAÇÃO DE PROGRAMA EM C PARA SISTEMAS EMBARCADOS
• Devemos ressaltar que nem sempre será possível alocar todas as variáveis em registradores.
• A palavra-chave register é apenas uma orientação para auxiliar o compilador a decidir quais variáveis são mais prioritárias para a alocação em registradores.
• Por este motivo é importante ter um código modular, com funções pequenas e específicas, para que a quantidade de variáveis locais também seja pequena, aumentando as chances de que estas sejam otimizadas através do armazenamento em registradores.
OTIMIZAÇÃO DE PROGRAMA EM C PARA SISTEMAS EMBARCADOS
B) Funções
• Uma chamada de função é um processo complexo e deve ser levado em consideração quando pensamos em performance. Basicamente, antes de uma chamada à função o compilador salva em memória (ou registradores) os argumentos da função e o endereço de retorno.
OTIMIZAÇÃO DE PROGRAMA EM C PARA SISTEMAS EMBARCADOS
• Essa região de memória é chamada de stack. Dentro da função chamada, os registradores são salvos, parâmetros são lidos do stack ou de registradores, e variáveis locais são alocadas em memória ou em registradores (se disponíveis).
• Podemos perceber que, para funções com uma quantidade grande de parâmetros, o custo de uma chamada pode ser enorme para a performance do sistema.
OTIMIZAÇÃO DE PROGRAMA EM C PARA SISTEMAS EMBARCADOS
• Uma das técnicas para melhorar a performance é diminuir a quantidade de parâmetros passados para funções.
• Podemos perceber comparando as duas funções abaixo, que o custo de chamada da função atualiza_dados(), com 5 parâmetros, é muito maior que o custo de chamada da função atualiza_dados_otimizada(), que recebe apenas um ponteiro para uma estrutura de dados como parâmetro.
OTIMIZAÇÃO DE PROGRAMA EM C PARA SISTEMAS EMBARCADOS
void atualiza_dados(char *nome, char *endereco, char *cidade, char *telefone, double salario)
{ ... } struct Dados { char *nome; char *endereco; char *cidade; char *telefone; double salario; }; void atualiza_dados_otimizada(struct *Dados) { ... }
OTIMIZAÇÃO DE PROGRAMA EM C PARA SISTEMAS EMBARCADOS
C) Inlining de funções: • A chamada à função é substituída por uma cópia do
seu código. Em código C, podemos empregar este recurso através da definição de macros.
• No primeiro exemplo, a função soma() será chamada 100 vezes, diminuindo a performance do sistema. No segundo exemplo, usa-se a macro SOMA(), eliminando a chamada à função e conseqüentemente aumentando a performance do sistema.
OTIMIZAÇÃO DE PROGRAMA EM C PARA SISTEMAS EMBARCADOS
#define SOMA(a, b) (a + b) int soma(int a, int b) { return(a + b); } int main() { int i, res, a = 1; /* primeiro exemplo */ for (i = 0; i < 100; i++) res = soma(a, res);
/* segundo exemplo */ for (res = 0, i < 100; i++) res = SOMA(a, res); ... }
OTIMIZAÇÃO DE PROGRAMA EM C PARA SISTEMAS EMBARCADOS
D) Otimização do compilador O compilador pode ser instruído para compilar o programa priorizando tempo de processamento (speed optimization) ou tamanho de código (size optimization).
• Como exemplo, vamos acompanhar a tabela, que lista informações sobre a compilação de dois programas distintos:
OTIMIZAÇÃO DE PROGRAMA EM C PARA SISTEMAS EMBARCADOS
• O programa 1 ficou menor quando selecionada a otimização por tamanho de código;
• O programa 2 ficou menor quando selecionada a otimização por tempo de processamento!
• Isso significa que é sempre bom testar as duas opções no seu código e verificar os resultados, antes de definir a otimização ótima para seu projeto.
OTIMIZAÇÃO DE PROGRAMA EM C PARA SISTEMAS EMBARCADOS
E) Tamanho das variáveis• o compilador é preparado para compilar o código
otimizado para a arquitetura-alvo do seu sistema.• Isso significa que se você está trabalhando com um
microprocessador de 8 bits, os cálculos terão maior performance se realizados com 8 bits de dados, em variáveis do tipo char.
• Da mesma forma, se você estiver trabalhando com processadores de 32 bits, os cálculos terão maior performance se realizados com variáveis do tipo int.
OTIMIZAÇÃO DE PROGRAMA EM C PARA SISTEMAS EMBARCADOS
• Isso acontece porque o compilador realiza os cálculos com base no tamanho de seus registradores, que por sua vez são baseados na arquitetura da CPU.
• Se a sua CPU é de 32 bits, seus registradores serão de 32 bits, e se você está realizando cálculos com variáveis char, de 8 bits, nesta arquitetura, o compilador terá o esforço extra de converter o resultado final, de 32 bits, em uma variável de 8 bits.
OTIMIZAÇÃO DE PROGRAMA EM C PARA SISTEMAS EMBARCADOS
F) Incremento de variáveis • É muito mais eficiente incrementar variáveis com o
uso de operadores de incremento (ex: ind++) do que o comando de atribuição (ex: ind = ind + 1).
• Isso porque a maioria dos compiladores usam , se disponível, a instrução de incremento do processador, o que torna o código-objeto gerado muito mais otimizado. Exemplo:
OTIMIZAÇÃO DE PROGRAMA EM C PARA SISTEMAS EMBARCADOS
/* incremento com atribuicao */ x = x + 1; /* codigo gerado em assembly mov A, x ; carrega o valor de x no registrador A add A, 1 ; soma 1 ao registrador A mov x, A ; carrega de volta o valor do registrador A em x */
/* operador de incremento */ x++; /* codigo gerado em assembly inc x; incrementa x em 1 */
OTIMIZAÇÃO DE PROGRAMA EM C PARA SISTEMAS EMBARCADOS
G) Protótipos para funções • Se o protótipo da função não é devidamente
definido, o compilador precisará “adivinhar” quais os tipos de dados com que sua função trabalha, o que diminui bastante a performance do sistema.
OTIMIZAÇÃO DE PROGRAMA EM C PARA SISTEMAS EMBARCADOS
H) Códigos muito “inteligentes” • Alguns programadores acreditam que, ao escrever
em poucas linhas de código fazendo uso “inteligente” de construções complexas em linguagem C, deixarão o código menor e mais rápido.
• Cuidado nem sempre o compilador vai criar códigos menores e pode tornar o código quase indecifrável!
OTIMIZAÇÃO DE PROGRAMA EM C PARA SISTEMAS EMBARCADOS
I) Uso de bibliotecas• Algumas vezes, o uso de apenas uma função de uma
biblioteca, como printf() pode trazer junto com ela, implicitamente, outras funções necessárias para sua utilização, e isso pode aumentar bastante o tamanho do seu código.
• Quando se trata de sistemas embarcados com poucos recursos disponíveis, às vezes é melhor implementar uma função simples do que utilizar a de uma biblioteca que pode fazer o tamanho do código crescer.
Exercício
• Completar a tabela dos tipos de dados do JM60 e JM128.
• Utilize o CodeWarrior vrs. 10.2
JM60
JM128