A apresentação está carregando. Por favor, espere

A apresentação está carregando. Por favor, espere

Eiji Adachi Barbosa LES / DI / PUC-Rio Abril / 2011 Aula 15 Estrutura de Funções e Tratamento de Exceções.

Apresentações semelhantes


Apresentação em tema: "Eiji Adachi Barbosa LES / DI / PUC-Rio Abril / 2011 Aula 15 Estrutura de Funções e Tratamento de Exceções."— Transcrição da apresentação:

1 Eiji Adachi Barbosa LES / DI / PUC-Rio Abril / 2011 Aula 15 Estrutura de Funções e Tratamento de Exceções

2 Avisos Correção do questionário será entregue até o fim deste mês Próxima aula ( 20/abril/2011 ) haverá exercício em sala de aula valendo 1 ponto no T2 –Exercício em dupla (preferencialmente, a mesma dupla dos trabalhos) janeiro de 142 Eiji Adachi Barbosa

3 Sumário Definições básicas –O que é função? –Por que / para que usar funções? –Pilha de chamadas Finalização de uma função Função de Arrumação da casa Especificação de uma função –Especificação do acoplamento de uma função Tratamento de exceções –Em C –Em linguagens de programação contemporâneas janeiro de 143 Eiji Adachi Barbosa

4 Definições básicas O que é uma função? –Função é uma porção auto-contida de código que: possui um nome que pode ser chamado (ativado) de diversos lugares pode retornar zero ou mais valores pode depender de e alterar zero ou mais parâmetros pode alterar zero ou mais valores do estado do módulo –variáveis internas –variáveis globais pode criar, ler e destruir arquivos, etc... TIPO_RETORNO NOME_FUNCAO ( LISTA_PARAMETROS) { CORPO_FUNCAO } janeiro de 144 Eiji Adachi Barbosa

5 Definições básicas Por que / para que usar funções? –Princípio dividir para conquistar Dividir sistema em módulos Dividir algoritmo em funções Evitar códigos monolíticos –Reuso e manutenibilidade janeiro de 145 Eiji Adachi Barbosa

6 Definições básicas - Pilha de chamadas int main() void firstCall() int printf(const char *...) int main() { firstCall(); return 0; } void firstCall(){ printf("First Call\n"); secondCall(); return; } int secondCall(){ printf("Second Call\n"); thirdCall(); return 0; } char thirdCall(){ printf("Third Call\nOK, Thats enough.\n"); return '0; } janeiro de 146 Eiji Adachi Barbosa

7 int main() { firstCall(); return 0; } void firstCall(){ printf("First Call\n"); secondCall(); return; } int secondCall(){ printf("Second Call\n"); thirdCall(); return 0; } char thirdCall(){ printf("Third Call\nOK, Thats enough.\n"); return '0; } Definições básicas - Pilha de chamadas int main() void firstCall() int secondCall() int printf(const char *...) janeiro de 147 Eiji Adachi Barbosa

8 int main() { firstCall(); return 0; } void firstCall(){ printf("First Call\n"); secondCall(); return; } int secondCall(){ printf("Second Call\n"); thirdCall(); return 0; } char thirdCall(){ printf("Third Call\nOK, Thats enough.\n"); return '0; } Definições básicas - Pilha de chamadas int main() void firstCall() int secondCall() char thirdCall() int printf(const char *...) janeiro de 148 Eiji Adachi Barbosa

9 Finalização de funções Encerrando a execução de uma função: –Chegar ao fim de uma função void –O comando return Encerra a execução de uma função imediatamente Se um valor de retorno é informado, a função chamada (callee) retorna este valor para a função chamadora (caller) A transferência de controle é local, i.e., após o return o controle do fluxo de execução passa da função chamada para a função chamadora –O comando exit(int) Encerra a execução do programa 1.Executa em ordem reversa todas as funções registradas pela função int atexit( void (*func)(void) ) 2.Todos streams são fechados, todos arquivos temporários são apagados 3.O controle de execução retorna ao ambiente-hospedeiro (host enviornment) o valor inteiro passado como argumento 1.` janeiro de 149 Eiji Adachi Barbosa

10 janeiro de 14 Eiji Adachi Barbosa Finalização de funções Deve existir uma sub-estrutura de funções cuja raiz coordena o controle de alocação e liberação de recursos. Exemplo: pArq = AbrirArquivo( NomeArquivo ) ; if ( pArq != NULL ) { ProcessarArquivo( pArq ) ; FecharArquivo( pArq ) ; } /* if */ Devem ser liberados todos os espaços dinâmicos e recursos alocados e que não serão retornados, ou que não foram incorporados a uma estrutura de dados ancorada durante a execução –requer exame do código com vistas a verificar se existe algum caminho em que o espaço ou recurso perde a âncora quando a função termina a execução. 10

11 janeiro de 14 Eiji Adachi Barbosa Arrumação da casa: finalização do programa Ao terminar a execução de um programa todos os recursos alocados neste programa devem ser liberados, independentemente de como foi terminado o programa Exemplos: –arquivos abertos –memória alocada Deve ser restaurado estado do sistema para o que era antes de iniciar a execução do programa Função int atexit( void (*func)(void) ) 11

12 janeiro de 14 Eiji Adachi Barbosa Arrumação da casa: finalização do programa Assegurar a liberação de recursos alocados é particularmente complexo quando o programa utiliza funções de finalização capazes de cancelar a execução Pode-se utilizar um módulo de arrumação da casa (housekeeping), ou de finalização para ajudar a resolver De qualquer maneira é necessária disciplina ao programar 12

13 Especificação de uma função A especificação de uma função define sua interface conceitual, em termos de: –Objetivo da função –Acoplamento Identifica todos os itens da interface –Pré-condição (Assertivas de entrada) –Pós-condição (Assertivas de saída) –Requisitos Propriedades de desempenho a serem satisfeitas: tempo de resposta, capacidade de armazenamento... –Hipóteses Windows, Linux, Mac? 32bit, 64bit? janeiro de 1413 Eiji Adachi Barbosa Próxima aula, dia 25/04.

14 janeiro de 14 Eiji Adachi Barbosa Especificação do acoplamento Acoplamento –identifica todos os itens da interface e respectivos tipos não somente os elementos da assinatura –são exemplos de itens do acoplamento parâmetros recebidos parâmetros modificados (chamada por referência) valores retornados, condições de retorno dados globais manipulados e/ou modificados arquivos manipulados exceções sinalizadas cancelamentos realizados – exit( num ) 14

15 janeiro de 14 Eiji Adachi Barbosa Especificação do acoplamento: notação 1. De forma visual, tais como: modelo de componentes –comentários podem ser usados para indicar dados resultantes ou modificados 2. Interface em notação similar a uma linguagem de programação –listam-se como parâmetros todos os dados ao entrar independentemente se serão explícitos ou implícitos sem se preocupar com a forma de realizar –por exemplo: diz-se Tabela ao invés de pTabela, mesmo se fisicamente a tabela será identificada por um ponteiro para a sua cabeça –listam-se como saída todos os dados resultantes ou modificados –exemplo InserirSimbolo( tpTabela Tabela, tpSimbolo Simbolo ) tpTabela Tabela, tpIdSimb IdSimbolo, tpCondRet CondRet 15

16 janeiro de 1416 / 32 Eiji Adachi Barbosa Especificação do acoplamento: notação 3. Texto explanatório, separando entrada e saída InserirSimbolo( tpTabela Tabela, tpSimbolo Simbolo ) tpTabela Tabela, tpIdSimb IdSimbolo, tpCondRet CondRet Recebe dados Tabela - Tabela em que será inserido o símbolo Simbolo - Símbolo válido a inserir Produz resultados Se não ocorreu erro Se o símbolo era novo: Cria um idSimbolo diferente dos existentes Tabela acrescida do par Se o Simbolo já existia Tabela inalterada FimSe idSimbolo o id associado ao Simbolo Se ocorreu erro: Tabela inalterada idSimbolo = NIL_SIMBOLO FimSe CondRet ver tipo tpCondRetTabela

17 Tratamento de exceções Por que é importante tratar exceções? –Você pode irritar o seu usuário janeiro de 1417 Eiji Adachi Barbosa

18 Tratamento de exceções Por que é importante tratar exceções? –Você pode irritar o seu usuário janeiro de 1418 Eiji Adachi Barbosa

19 Tratamento de exceções Por que é importante tratar exceções? –Os usuários podem perder a confiança no seu produto –... e você pode passar uma tremenda vergonha! janeiro de 1419 Eiji Adachi Barbosa

20 Tratamento de exceções Vídeo do Bill Gates: –http://www.youtube.com/watch?v=TrAD25V7ll8http://www.youtube.com/watch?v=TrAD25V7ll8 janeiro de 1420 Eiji Adachi Barbosa

21 Tratamento de exceções Por que é importante tratar exceções? –Pode custar milhões de dólares/reais/euros –Ou até mesmo vidas janeiro de 1421 Eiji Adachi Barbosa

22 Tratamento de exceções janeiro de 1422 Eiji Adachi Barbosa Vídeo do Ariane 5: –http://www.youtube.com/watch?v=kYUrqdUyEpIhttp://www.youtube.com/watch?v=kYUrqdUyEpI

23 Tratamento de exceções - Caso de insucesso Em outubro de 1996 o foguete francês Ariane 501 se autodestruiu 5 minutos após decolar Motivo: –cálculo errado do ângulo de ataque Causa: –O Ariane 5 reutilizou um módulo do Ariane 4 para calcular o Alinhamento Interno, elemento relacionado com a componente horizontal da velocidade –O valor gerado pelo módulo do Ariane 4 foi muito maior do que o esperado pelo módulo do Ariane 5, pois a trajetória do Ariane 5 difere da trajetória do Ariane 4 –O módulo do Ariane 5 tentou converter o valor do Alinhamento Interno de um número de 64 bits em ponto flutuante para um inteiro de 16 bits com sinal –Valor em ponto flutuante era maior do que poderia ser representado por um inteiro –Operação de conversão não estava protegida –Overflow Exception janeiro de 1423 Eiji Adachi Barbosa

24 Tratamento de exceções Exemplos de tratadores: –recuperação por retrocesso: o tratador desfaz modificações nas variáveis locais e retorna um resultado indicando insucesso na operação –fechamento: o tratador garante que uma conexão/arquivo aberta(o) seja fechada(o) –notificação ao usuário: nenhuma recuperação, somente notifica ao usuário que uma exceção ocorreu –armazenamento de erro: criação de registro de erro em arquivo especial –re-sinaliza uma exceção diferente... Para a função chamadora –nova tentativa: a mesma função ou uma diferente implementação (daquela função) é invocada é usada em técnicas como bloco de recuperação ou programação N-Versões –tratador vazio: silencia a exceção – má pratica e deve ser evitado –assert: o tratador desempenha algum tipo de operação de assert; quanto a assertiva não é válida, isto resulta em uma nova exceção, possivelmente levando ao término da execução do programa janeiro de 1424 Eiji Adachi Barbosa

25 Como tratar exceções? Linguagens contemporâneas (Java, JavaScript, C++, C#, Python...) possuem mecanismos de tratamento de exceções implementados na própria linguagem –TRY-CATCH-FINALLY A linguagem C não traz suporte específico para tratamento de exceções, por isso o faz através de um idioma: –Testando condições de retorno –Modificando / testando variáveis globais ou parâmetros passados por referência janeiro de 1425 Eiji Adachi Barbosa São usados de forma complementar!

26 Testando condições de retorno O comando return é utilizado pela função chamada para indicar sob qual condição (normal | excepcional) sua execução encerrou A função chamadora deve testar o código retornado pela função chamada a fim de tomar ações corretivas, caso necessário Preferencialmente, as condições de retorno devem ser declaradas como um elemento enum janeiro de 1426 Eiji Adachi Barbosa

27 Testando condições de retorno typedef enum { LIS_CondRetOK, /* Concluiu corretamente */ LIS_CondRetListaVazia, /* A lista não contém elementos */ LIS_CondRetFimLista, /* Foi atingido o fim de lista */ LIS_CondRetNaoAchou, /* Não encontrou o valor procurado */ LIS_CondRetFaltouMemoria /* Faltou memória ao tentar criar um elemento de lista */ } LIS_tpCondRet ; LIS_tpCondRet LIS_InserirElementoAntes ( LIS_tppLista pLista, void * pValor ) { tpElemLista * pElem ; pElem = CriarElemento( pLista, pValor ) ; if ( pElem == NULL ) { return LIS_CondRetFaltouMemoria ; } /* if */.... return LIS_CondRetOK ; } /* Fim função: LIS &Excluir elemento */ janeiro de 1427 Eiji Adachi Barbosa

28 Testando condições de retorno int main(void){... LIS_tpCondRet condRet = InserirElementoAntes( lista, pValor ); switch( condRet ) { case LIS_CondRetFaltouMemoria:... case LIS_CondRetOK:... default : printf(Condição de retorno inesperada); } janeiro de 1428 Eiji Adachi Barbosa

29 Usando variáveis globais ou parâmetros A função chamada deve modificar variáveis globais ou parâmetros passados por referência para indicar sob qual condição (normal | excepcional) sua execução encerrou A função chamadora deve testar a variável global, ou o parâmetro passado por referência, a fim de tomar ações corretivas, caso necessário janeiro de 1429 Eiji Adachi Barbosa

30 Usando parâmetro passado por referência LIS_tpCondRet LIS_InserirElementoAntes ( LIS_tppLista pLista, void * pValor, char ** errorMsg ) { tpElemLista * pElem ; pElem = CriarElemento( pLista, pValor ) ; if ( pElem == NULL ) { char str[] = Não foi possível alocar memória para um novo elemento; int size = strlen( str ) + 1; (*errorMsg) = (char*)malloc( sizeof(char) * size ); memcpy( (*errorMsg), str, size ); return LIS_CondRetFaltouMemoria ; } /* if */.... return LIS_CondRetOK ; } /* Fim função: LIS &Excluir elemento */ Usar uma variável global, seria análogo... janeiro de 1430 Eiji Adachi Barbosa

31 Usando parâmetro passado por referência int main(void){... char *errorMsg; LIS_tpCondRet condRet = InserirElementoAntes( lista, pValor, &errorMsg ); switch( condRet ) { case LIS_CondRetFaltouMemoria: printf( %s, errorMSG ); case LIS_CondRetOK:... default : printf(Condição de retorno inesperada); } Usar uma variável global, seria análogo... janeiro de 1431 Eiji Adachi Barbosa

32 Limitações de C A sinalização de uma exceção não é explícita –Usa-se o comando return, parâmetros passados por referência ou variáveis globais Nem sempre é possível retornar um elemento enumerado como condição de retorno –Ex.: Trabalho 1 – Implemente uma função que receba os três parâmetros (Nome, Iniciais, Idade) e retorne por referência a estrutura preenchida. Como prover mais informações a respeito do problema / exceção? –Ex.: Qual a severidade? Que condições levaram a esta ocorrência? janeiro de 1432 Eiji Adachi Barbosa

33 Limitações de C Há um overhead na criação de tipos enumerados para cada módulo A associação entre as exceções descritas nos tipos enumerados e quais exceções que podem ser levantadas por uma função depende exclusivamente da especificação da função –Difícil entender o acoplamento excepcional entre funções: quais exceções devem ser tratadas? Não há separação textual do código de tratamento de exceção –Código torna-se rapidamente extenso, complexo e pouco compreensível Como assegurar que as pós-condições da função serão satisfeitas, mesmo em casos excepcionais? janeiro de 1433 Eiji Adachi Barbosa

34 Linguagens contemporâneas Linguagens como Java, JavaScript, C++, C#, Python... provêem mecanismos de tratamento de exceções implementados na própria linguagem –TRY – define uma região protegida contra a ocorrência de exceções –CATCH – define um tratador, i.e., um trecho de código que implementa um conjunto de ações de recuperação –FINALLY – define um trecho de código que sempre será executado, mesmo quando exceções ocorrerem –THROW – sinaliza a ocorrência de uma exceção –THROWS – especifica o acoplamento excepcional de uma função janeiro de 1434 Eiji Adachi Barbosa

35 Acoplamento excepcional explícito static void escreveArquivo(Arquivo) throws FileNotFoundException, CharCodingException, PermissionException; janeiro de 1435 Eiji Adachi Barbosa

36 Sinalização explícita de exceções static void escreveArquivo(Arquivo a) throws FileNotFoundException, CharCodingException, PermissionException { Buffer bf = buscaArquivo( a ); if( bf == null ) throw new FileNotFoundException(); } janeiro de 1436 Eiji Adachi Barbosa

37 Melhor separação textual ARQ_tpCondRet leArquivo(){ condRet = OK; abreArquivo(); se( arquivoAberto() ){ determineTamanhoArquivo(); se( determinouTamanho() ){ aloqueMemoria(); se( alocouMemoria() ){ copieDados(); se( ! copiouDados() ){ condRet = ERRO_COPIAR_DADOS; } } senão { condRet = ERRO_ALOCAR_MEM; } } senão { condRet = ERRO_DET_TAM; } fecheArquivo(); se( ! fechouArquivo() ){ condRet = ERRO_FECHAR_ARQ; } } senão { condRet = ERRO_ABRIR_ARQ; } leArquivo(){ try{ abreArquivo(); determineTamanhoArquivo(); aloqueMemoria(); copieDados(); } catch( abrirErro ){...} catch( determinarTamanhoErro ) {...} catch( alocarMemoriaErro ) {...} catch( copiarDadosErro ) {...} finally { try{ fecheArquivo(); } catch( fecharArquivoErro ){...} } janeiro de 1437 Eiji Adachi Barbosa

38 Lista preencheLista(){ Arquivo arq = null; Lista lista = null; try{ arq = abreArquivo( Dados.txt ); lista = criaLista(); for( i=0; i<SIZE; i++ ){ adiciona( lista, arq, i ); } //faz mais alguma coisa } catch( RegistroException ){ print( Registro lido incorretamente ); } finally { if( arq != null){ fechaArquivo( arq ); } return lista; } void adiciona(Lista lista, Arquivo arq, int i ) throws RegistroException { Registro r = leRegistro( arq, i ); Elemento e = criaElement( r ); adicionaElemento( lista, e, i ); } Execução e transferência não-local preecheLista() finally catch( RegistroException ) janeiro de 1438 Eiji Adachi Barbosa

39 Lista preencheLista(){ Arquivo arq = null; Lista lista = null; try{ arq = abreArquivo( Dados.txt ); lista = criaLista(); for( i=0; i<SIZE; i++ ){ adiciona( lista, arq, i ); } //faz mais alguma coisa } catch( RegistroException ){ print( Registro lido incorretamente ); } finally { if( arq != null){ fechaArquivo( arq ); } return lista; } void adiciona(Lista lista, Arquivo arq, int i ) throws RegistroException { Registro r = leRegistro( arq, i ); Elemento e = criaElement( r ); adicionaElemento( lista, e, i ); } Execução e transferência não-local preecheLista() finally catch( RegistroException ) abreArquivo janeiro de 1439 Eiji Adachi Barbosa

40 Lista preencheLista(){ Arquivo arq = null; Lista lista = null; try{ arq = abreArquivo( Dados.txt ); lista = criaLista(); for( i=0; i<SIZE; i++ ){ adiciona( lista, arq, i ); } //faz mais alguma coisa } catch( RegistroException ){ print( Registro lido incorretamente ); } finally { if( arq != null){ fechaArquivo( arq ); } return lista; } void adiciona(Lista lista, Arquivo arq, int i ) throws RegistroException { Registro r = leRegistro( arq, i ); Elemento e = criaElement( r ); adicionaElemento( lista, e, i ); } Execução e transferência não-local preecheLista() finally catch( RegistroException ) criaLista janeiro de 1440 Eiji Adachi Barbosa

41 Lista preencheLista(){ Arquivo arq = null; Lista lista = null; try{ arq = abreArquivo( Dados.txt ); lista = criaLista(); for( i=0; i<SIZE; i++ ){ adiciona( lista, arq, i ); } //faz mais alguma coisa } catch( RegistroException ){ print( Registro lido incorretamente ); } finally { if( arq != null){ fechaArquivo( arq ); } return lista; } void adiciona(Lista lista, Arquivo arq, int i ) throws RegistroException { Registro r = leRegistro( arq, i ); Elemento e = criaElement( r ); adicionaElemento( lista, e, i ); } Execução e transferência não-local preecheLista() finally catch( RegistroException ) adiciona leRegistro janeiro de 1441 Eiji Adachi Barbosa

42 Lista preencheLista(){ Arquivo arq = null; Lista lista = null; try{ arq = abreArquivo( Dados.txt ); lista = criaLista(); for( i=0; i<SIZE; i++ ){ adiciona( lista, arq, i ); } //faz mais alguma coisa } catch( RegistroException ){ print( Registro lido incorretamente ); } finally { if( arq != null){ fechaArquivo( arq ); } return lista; } void adiciona(Lista lista, Arquivo arq, int i ) throws RegistroException { Registro r = leRegistro( arq, i ); Elemento e = criaElement( r ); adicionaElemento( lista, e, i ); } Execução e transferência não-local preecheLista() finally catch( RegistroException ) adiciona leRegistro Esse trecho de código não é executado! janeiro de 1442 Eiji Adachi Barbosa

43 Lista preencheLista(){ Arquivo arq = null; Lista lista = null; try{ arq = abreArquivo( Dados.txt ); lista = criaLista(); for( i=0; i<SIZE; i++ ){ adiciona( lista, arq, i ); } //faz mais alguma coisa } catch( RegistroException ){ print( Registro lido incorretamente ); } finally { if( arq != null){ fechaArquivo( arq ); } return lista; } void adiciona(Lista lista, Arquivo arq, int i ) throws RegistroException { Registro r = leRegistro( arq, i ); Elemento e = criaElement( r ); adicionaElemento( lista, e, i ); } Execução e transferência não-local preecheLista() finally print Esse trecho de código não é executado! catch( RegistroException ) janeiro de 1443 Eiji Adachi Barbosa

44 Lista preencheLista(){ Arquivo arq = null; Lista lista = null; try{ arq = abreArquivo( Dados.txt ); lista = criaLista(); for( i=0; i<SIZE; i++ ){ adiciona( lista, arq, i ); } //faz mais alguma coisa } catch( RegistroException ){ print( Registro lido incorretamente ); } finally { if( arq != null){ fechaArquivo( arq ); } return lista; } void adiciona(Lista lista, Arquivo arq, int i ) throws RegistroException { Registro r = leRegistro( arq, i ); Elemento e = criaElement( r ); adicionaElemento( lista, e, i ); } Execução e transferência não-local preecheLista() finally fechaArquivo Esse trecho de código não é executado! janeiro de 1444 Eiji Adachi Barbosa

45 Testes e exceções Dificuldade em testar código de tratamento de exceção: –Código tratador é pouco executado Exceções ocorrem raramente –Como lançar a exceção e testar o tratador? Descobrir quais assertivas devem ser quebradas Mecanismos de injeção de erros Qual ação esperada do tratador? janeiro de 1445 Eiji Adachi Barbosa

46 Referência Cap. 8 do livro Programação Modular janeiro de 1446 Eiji Adachi Barbosa

47 FIM janeiro de 1447 Eiji Adachi Barbosa


Carregar ppt "Eiji Adachi Barbosa LES / DI / PUC-Rio Abril / 2011 Aula 15 Estrutura de Funções e Tratamento de Exceções."

Apresentações semelhantes


Anúncios Google