===== Tratamento de erros =====
A linguagem C não é muito eloquente ao informar erros de execução. Contudo, existem mecanismos para detectar e informar sobre erros de execução, que são apresentados nesta página.
==== errno, perror e strerror ====
As chamadas de sistema e funções em C informam erros de execução retornando um valor inteiro negativo (como faz o ''printf'') ou um ponteiro nulo (como faz o ''malloc'') e ajustando uma variável predefinida chamada ''errno'' para indicar mais precisamente o erro ocorrido.
Os códigos de erro indicados pela variável ''errno'' são valores inteiros positivos que correspondem a macros e //strings// definidas na biblioteca C (no arquivo ''errno.h'' e outros). Em Linux, esses códigos, macros e strings podem ser consultados através do comando ''errno'' no terminal:
$ errno -l
EPERM 1 Operation not permitted
ENOENT 2 No such file or directory
ESRCH 3 No such process
EINTR 4 Interrupted system call
EIO 5 Input/output error
ENXIO 6 No such device or address
E2BIG 7 Argument list too long
ENOEXEC 8 Exec format error
EBADF 9 Bad file descriptor
ECHILD 10 No child processes
EAGAIN 11 Resource temporarily unavailable
ENOMEM 12 Cannot allocate memory
EACCES 13 Permission denied
... (+100 linhas)
Dessa forma, o erro ocorrido em uma chamada de função pode ser tratado de forma mais precisa pelo programa, como mostra este exemplo:
#include
#include
...
FILE* file ;
// abre arquivo de dados
file = fopen ("results.dat", "r+") ;
// erro na abertura do arquivo
if (! file)
{
switch (errno)
{
case EPERM : printf ("Operação não permitida\n") ; break ;
case ENOENT : printf ("Arquivo não encontrado\n") ; break ;
case EACCESS : printf ("Permissão negada\n") ; break ;
default:
printf ("Outro erro\n") ;
}
exit (1) ;
}
Para facilitar a geração de mensagens de erro, a função ''perror (char *msg)'' imprime na saída de erro (''stderr'') a string ''msg'' seguida da //string// de descrição do erro encontrado:
// abre arquivo de dados
file = fopen ("results.dat", "r+") ;
// erro na abertura do arquivo
if (! file)
{
perror ("Erro no fopen") ;
exit (1) ;
}
Caso o arquivo ''results.dat'' não exista, o código acima irá gerar esta saída:
Erro no fopen: No such file or directory
Para produzir mensagens de erro mais elaboradas, pode-se usar a função ''strerror (int num)'', que retorna uma //string// com a descrição do erro cujo código é ''num''.
O valor de ''errno'' (e portanto a saída de ''perror'') se refere à última função chamada e pode mudar após a próxima chamada de função. Por isso, é importante testar ''errno'' imediatamente após o retorno da função, antes de chamar outra função.
==== Funções exit, abort e assert ====
A execução de um programa em C pode ser finalização pela conclusão/retorno da função ''main'' ou por chamadas a funções específicas como ''exit'', ''abort'' ou ''assert'', discutidas nesta seção.
Quando um programa em C encerra, ele devolve um status de saída (//exit status//) ao processo que o lançou, que pode ser o terminal/shell, um script ou outro programa. No terminal ou em scripts, o status de saída de um programa que acabou de encerrar pode ser consultado através da variável de ambiente ''$?''.
A função ''exit (int status)'' encerra o programa e devolve o valor ''status & 0xFF'' ao processo que o lançou. Ao encerrar, todos os arquivos abertos são fechados e sincronizados, para evitar a perda de dados. Os //sockets// de rede, áreas de memória dinâmica e outros recursos alocados também são liberados.
Exemplo:
// abre arquivo de dados
file = fopen ("results.dat", "r+") ;
// erro na abertura do arquivo
if (! file)
{
perror ("Erro no fopen") ;
exit (2) ;
}
O status de saída do programa pode ser consultado no shell:
$ programa
Erro no fopen: No such file or directory
$ echo $?
2
Pode-se usar a função ''atexit'' para definir uma ou mais funções a executar automaticamente quando um programa encerra por ''exit'' ou por retorno da função ''main'':
#include
#include
// mensagem de saída
void msg_saida ()
{
printf ("O programa encerrou\n") ;
}
int main ()
{
// registra função a executar no "exit"
atexit (msg_saida) ;
printf ("O programa iniciou\n") ;
}
Pode-se encerrar de forma mais "abrupta" um programa através da função ''abort ()'', que não sincroniza os dados dos arquivos abertos pelo programa, não executa as funções definidas por ''atexit'' e retorna um status de saída não-nulo ao processo-pai.
Por fim, ''assert'' é uma função que verifica uma asserção (condição) e encerra o programa se ela for falsa (nula). Ao encerrar, uma mensagem de erro indicando a localização da asserção violada é gerada, o que facilita localizar problemas.
#include
int main()
{
...
assert (i >= 0) ; // só continua se i >= 0
...
}
Se a condição ''i >= 0'' for falsa ao ser avaliada por ''assert'', o programa será interrompido e a seguinte mensagem será gerada, indicando o arquivo (''program.c''), a linha (6), a função (''main'') e a asserção violada:
a.out: program.c:6: main: Assertion `i >= 0' failed.