quarta-feira, 28 de novembro de 2012

Exceções em C



Uma exceção é um sinal que indica que algum tipo de condição excepcional ocorreu durante a execução do programa. Assim, exceções estão associadas a condições de erro que não tinham como ser verificadas durante a compilação do programa.

Algumas linguagem possuem facilidades de tratamento de exceção, como por exemplo, Java, ADA,
Python e Ruby. A linguagem C carece dessa facilidade de tratamento de exceção.

Na linguagem C, outros métodos pode ser usado para indicar exceções e tratá-las. Uns dos métodos mais utilizados é funções que retornam status code ou "funny values" para indicar condições excepcionais.


#include

int main(){
 int * p;

 p = (int * )malloc(10*sizeof(int));

 if(!p){
  printf("Memória insuficiente\n");
 }else{
  printf("Memória alocada com sucesso\n");
 }

}


Esse método não permite detectar e tratar outros tipos de exceções, como por exemplo, divisão por zero.
Para detectar e tratar esse tipo de exceção, vamos utilizar os UNIX Signal. Para isso, precisamos definir tratador de exceção que vai ser invocado quando um sinal do sistema for recebido.

Ponteiro para um função de tratamento do sinal. A função de tratamento recebe um sinal int que é o sinal que ela trata
typedef void (*__p_sig_fn_t)(int);  


Associa ao sinal int a uma função que trata o sinal __p_sig_fn_t.
_CRTIMP __p_sig_fn_t __cdecl signal(int, __p_sig_fn_t);


Sinais que podem ser detectados

#define SIGINT 2 /* Interactive attention */
#define SIGILL 4 /* Illegal instruction */
#define SIGFPE 8 /* Floating point error */
#define SIGSEGV 11 /* Segmentation violation */
#define SIGTERM 15 /* Termination request */
#define SIGBREAK 21 /* Control-break */
#define SIGABRT 22 /* Abnormal termination (abort) */

Exemplo
#include <stdio.h> 
#include <stdlib.h>
#include <signal.h>

void float_error(int i){
 signal(SIGFPE, float_error);
 printf("You have raised a floating point error\n"); 
 exit(0);
}

int main(){
  int a,b;
    
  signal(SIGFPE, float_error );

  scanf("%d %d",&a,&b);
  
  printf("%d\n",a/b); 

  return 0;
}



Entrada
2 0

Saída
2 0
You have raised a floating point error
Pressione qualquer tecla para continuar. . .

Entrada
4 2
Saída
2


Tratamento de Exceção

Para realizar o tratamento de exceção, precisamos usar setjmp salvar o ambiente no ponto que  ocorreu a exceção e usar longjmp (non-local goto) para realizar seu trabalho do mal.

/*
 * The buffer used by setjmp to store the information used by longjmp
 * to perform it's evil goto-like work. The size of this buffer was
 * determined through experimentation; it's contents are a mystery.
 * NOTE: This was determined on an i386 (actually a Pentium). The
 *       contents could be different on an Alpha or something else.
 */
#define _JBLEN 16
#define _JBTYPE int
typedef _JBTYPE jmp_buf[_JBLEN];


/*
 * The function provided by CRTDLL which appears to do the actual work
 * of setjmp.
 */
_CRTIMP int __cdecl _setjmp (jmp_buf);


/*
 * Return to the last setjmp call and act as if setjmp had returned
 * nVal (which had better be non-zero!).
 */
_CRTIMP void __cdecl longjmp (jmp_buf, int) __MINGW_ATTRIB_NORETURN;

Exemplo

#include
#include
#include
#include
int a,b;
jmp_buf env;


int main(){
  
  void float_error(int);
  
  signal(SIGFPE, float_error );

  setjmp(env);

  scanf("%d %d",&a,&b);
  
  printf("%d\n",a/b); 

  return 0;
}

void float_error(int i){
 signal(SIGFPE, float_error);
 printf("You have raised a floating point error\n"); 
 printf("Entre com novos valores:\n");
 longjmp(env,0);
}

Execução

2 0
You have raised a floating point error
Entre com novos valores:
4 2
2

Outras referências:
http://www.vivaolinux.com.br/artigo/Tratamento-de-excecoes-na-linguagem-C?pagina=1 

http://sergioprado.org/tratamento-de-erros-em-linguagem-c/ 

http://www.vivaolinux.com.br/script/Excecoes-em-C-atraves-de-trythrowcatch


Nenhum comentário: