Você está na página 1de 61

Linguagem C

Disciplina: AAM
Profa. Ana Watanabe
17/02/20
 “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
 Anos 70 de uma linguagem chamada B
por Dennis Ritchie.

 Qualquer programa C ANSI pode ser


compilado em qualquer compilador C
ANSI não importando onde o programa
vai ser rodado.

 Portanto => portabilidade


Revisão da Linguagem C
 Criada por programadores.

 Características:poucas restrições,
código rápido e eficiência.

É 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.
Revisão da Linguagem C

 Declaração de variáveis: Variáveis devem ser


declaradas antes de serem usadas
(compilador saber de antemão);
Revisão da Linguagem C
 Funções: Blocos de Código: Conjunto de
comandos que executa uma determinada
operação no programa.

 Útil quando se necessita repetir um mesmo


trecho de código várias vezes em um
programa.
Revisão da Linguagem C
 Sensitive case: 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
Palavras reservadas:
auto  else  register  un
break  enum  return  un
case  extern  short  vo
char  float  signed  vo
const  for  sizeof  wh
continued goto  static
efault  if struct 
do int  switch 
double  long   typedef 
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
 ESTRUTURA BÁSICA DE UM PROGRAMA:

1) INCLUSÃO DE ARQUIVOS EXTERNOS

2) DECLARAÇÃO DE VARIÁVEIS GLOBAIS

3) DECLARAÇÃO DE PROTÓTIPOS DE FUNÇÕES

4) 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( ).

• 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
#include <stdio.h>

float Square (float a)


{
return (a*a);
}

int main ( )
{
float num;
num=Square(num);
return 0;
}
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>

int main ( ) // Tem algum problema?


{ // Como resolver??
float num;
num=Square(num);
return 0;
}
float Square (float a)
{
return (a*a);
}
Revisão da Linguagem C
#include <stdio.h>
float Square (float a); // protótipo
int 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 )
 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-linguage
m-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 transformar os algoritmos


(código-fonte C) em aplicação.

 O compilador realiza uma série de transformações


no código-fonte para gerar o melhor código
possível: Ex.: salva 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.
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: 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.
 Ex.:
 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: 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: 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

 Etapas para otimização:


 Etapa 2 (Otimização de alto nível) e
 Etapa 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.
 => 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
 Pode-se instruir o compilador através da palavra-
chave register, conforme mostra o código:

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).

 Funções com uma quantidade grande de


parâmetros => custo de uma chamada pode ser
enorme para a performance do sistema.
OTIMIZAÇÃO DE PROGRAMA EM C
PARA SISTEMAS EMBARCADOS
 Como melhorar a performance?
 Diminuir a quantidade de parâmetros passados
para funções.

 O custo de chamada da função atualiza_dados()


com 5 parâmetros >> 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)
{
...
}  //

OU
OTIMIZAÇÃO DE PROGRAMA EM C
PARA SISTEMAS EMBARCADOS
//OU
typedef struct {
char nome;
char endereco;
char cidade;
char telefone;
double salario;
}tdados;  

void atualiza_dados_otimizada(tdados *cliente)


{
... cliente->nome = “Maria”;
}
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 através da definição de macros.

 No primeiro exemplo, a função soma( ) será


chamada 100 vezes, diminuindo a performance do
sistema.
OTIMIZAÇÃO DE PROGRAMA EM C
PARA SISTEMAS EMBARCADOS
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);
}
OTIMIZAÇÃO DE PROGRAMA EM C
PARA SISTEMAS EMBARCADOS
C) Inlining de funções:

 Como usar macros 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) // macro  


OTIMIZAÇÃO DE PROGRAMA EM C
PARA SISTEMAS EMBARCADOS
Como reescrever o código?????

int main( ) {
int i, res, a = 1;  

}
OTIMIZAÇÃO DE PROGRAMA EM C
PARA SISTEMAS EMBARCADOS
#define SOMA(a, b) (a + b)  

int main( ) {
int i, res, a = 1;  

for (i = 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).

 É 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 compila o código otimizado para a

arquitetura-alvo do seu sistema.


 Se o 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
 Por que? 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 (registradores de 32


bits), e se você está realizando cálculos com
variáveis char (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
*/  
OTIMIZAÇÃO DE PROGRAMA EM C
PARA SISTEMAS EMBARCADOS

/* 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
 O uso da função de uma biblioteca, ex.: printf( )

pode trazer junto com ela, implicitamente, outras


funções necessárias para sua utilização=> pode
aumentar muito o tamanho do seu código.

 Portanto, sistemas embarcados com poucos


recursos disponíveis => melhor implementar
uma função simples sem uso de uma biblioteca.
Exercício para nivelamento:
 Escreva um programa que faça o seguinte:

 1)Crie uma função que retorna um valor após decrementar


b vezes o parâmetro de entrada a. Exemplo: int função
(a,b).

 2) Faça uma nova versão utilizando endereço da estrutura


(ponteiro) como parâmetro de entrada para otimização.

Use protótipo, operador de decremento e registradores


para otimizar!!!
Sugestão da parte 1:

#include <avr/io.h>

int sub(register int a, register int b); // protótipo

void main (void)


{
register int a,b, resultado;

a = 10;
b= 3;
resultado=sub(a,b);
}

int sub(register int a,register int b)


{
register int i;
for (i = 0; i < b; i++)
a--;
return (a);
}


Sugestão do 2: #include <avr/io.h>
typedef struct {
int a;
int b;
} tvalores;

int sub(tvalores *c); // protótipo

void main (void)


{
tvalores conta;
int resultado;

conta.a = 10;
conta.b= 3;
resultado=sub(&conta);
}

int sub (tvalores *c)


{
int i;
for (i = 0; i < c->b; i++)
c->a--;

Você também pode gostar