Pular para o conteúdo

Tratamento de exceções na linguagem C

Uma implementação de tratamento de exceções usando a linguagem C, discutindo vários modelos e suas limitações, possíveis vazamentos de memórias, testes comparativos, muitos exemplos, introdução a certos recursos da linguagem, ... É certamente um assunto interessante se você quer expandir seus conhecimentos da linguagem C.
Vinícius dos Santos Oliveira vinipsmaker
Hits: 72.774 Categoria: C/C++ Subcategoria: Avançado
  • Indicar
  • Impressora
  • Denunciar

Introdução

Em linguagens de programação de alto nível tais como C++, Python e Java, há o recurso de tratamento de exceções, que permite que programadores escrevam blocos try - catch e funções/métodos que disparem exceções.

Com uso de tais recursos, o fluxo de lógica do programa fica no bloco try, separado do tratamento das exceções, que ficam no bloco catch. O uso primário do tratamento de exceções é separar o fluxo da lógica do fluxo de tratamento de erros (nesse caso usa-se exceções para identificar os erros). Dentro dessa abordagem, as exceções são usadas para indicar erros que ocorrem. Tratamento de exceções, atualmente, é uma técnica desejável em muitos ambiente de desenvolvimento.

Programadores de C, geralmente utilizam o valor de retorno da função para indicar algum erro, como ocorre nas funções de alocação dinâmica, por exemplo. Essa abordagem é adequada a proposta da linguagem de ser uma linguagem de médio nível eficiente, porém nem sempre é adequada ao desenvolvimento do software. Em uma função onde todo valor de retorno é válido, essa abordagem mostra-se ineficaz, e a elegância do código seria ameaçada para resolver tal problema, como mostra o exemplo.

int divide1(int a, int b, int *ok)
{
  if (b) {
    if (ok)
      *ok = 1;
    return a / b;
  } else {
    if (ok)
      ok = 0;
    return 0;
  }
}

struct ret
{
  int ok;
  int value;
};

struct ret divide2(int a, int b)
{
  struct ret res = {1, 0};

  if (b)
    res.value = a / b;
  else
    res.ok = 0;

  return res;
}

int main()
{
  int i;
  {
    int ok;
    // A and B should be defined as macros
    int unsafe_value = divide1(A, B, &ok);
    if (ok)
      i = unsafe_value;
  }
  {
    struct ret tmp = divide2(A, B);
    if (tmp.ok)
      i = tmp.value;
  }
  return 0;
}

Uma prática que vem substituindo com sucesso o uso de valores de retorno para a indicação de erros é o uso de exceções. Essa prática traz vários benefícios, principalmente relacionados com a legibilidade e manutenção do código.

Neste texto, serão demonstradas as funcionalidades requeridas para que o tratamento de exceções seja aplicado e será feita a apresentação de uma implementação na linguagem de programação C, que é uma das linguagens de médio nível mais populares. Por ser uma linguagem de médio nível, adotar tratamento de exceções como parte do padrão que define a linguagem pode não ser adequado, pois o código-fonte iria esconder certos comportamentos, que não é característico em uma linguagem de médio nível.

Assim sendo, este artigo tem por objetivo:

i) apresentar técnicas que imitem o tratamento de exceções que expõem a implementação proposta;
ii) descrever facilidades implementadas através de macros que viabilizam seu uso e;
iii) avaliar o desempenho.

Nesse texto foi adotada uma abordagem incremental, onde há uma definição simples do tratamento de exceções no início, e a cada seção teremos uma definição mais próxima da utilizada na programação no mundo real.

   1. Introdução
   2. Tratamento de exceções em C
   3. Quebra de fluxo de execução, goto e setjmp
   4. Exceções associadas a inteiros
   5. Informação sobre os tipos em tempo de execução
   6. Macros
   7. Aninhando exceções
   8. Mais macros
   9. Memory leaks
   10. Uso em dispositivos móveis
   11. Conclusão

Mupen64plus, o melhor emulador de Nintendo 64 disponível para GNU/Linux

A história do ogg na web

Próximas Tecnologias do Sistema GNU/Linux

História da informática: Um pouco de datas e especificações

VLC Media Player (parte 2)

Utilizando técnicas recursivas em C e C++

Cuidado com números em Ponto Flutuante

Criando aplicativos para o iPhone no Linux (sem Xcode e MacOS X)

Tutorial OpenGL v3.0

Desenvolvendo aplicativo para autenticação biométrica utilizando a Libfprint

#1 Comentário enviado por removido em 11/11/2010 - 17:16h
Gostei da aparência do código usando macros para definir os blocos try, catch e throw.

E parabéns pela contribuição de suas idéias!
#3 Comentário enviado por SamL em 12/11/2010 - 12:06h
Cara gostei do artigo, nota 10.
Usar essas macros deixa um código bem mais limpo e organizado.
#4 Comentário enviado por gedarius em 12/11/2010 - 12:06h
ótimo artigo, parabéns!!!!
#5 Comentário enviado por vinipsmaker em 12/11/2010 - 15:47h
@mslomp, vlw, é bom saber que esse assunto interessa a muitos.

E aos outros, agradeço os elogios (críticas também são bem-vindas, caso tenham alguma =D ).
#6 Comentário enviado por mazinsw em 12/11/2010 - 19:41h
valeu pela contribuição, eu não sabia usar macros agora está mais fácil.

Contribuir com comentário

Entre na sua conta para comentar.