C/errno

< C
(Redirección desde «C/Manexo de erros»)


A linguaxce de programación C non conta con soporte nativo para manexo de erros (tamén coñecido como manexo de excepcións). Debe ser o propio programador o que preveña a ocurrencia de erros en primeiro lugar, a miúdo poñendo a proba os posaibles valores das funcións. -1 e NULL úsanse en moitas funcións tales coma socket() ou malloc() respectivamente para indicar problemas dos que o programador xa debería saber. Nun caso peor en que o erro é inevitable e non hai xeito de recuperarse del, o programador en C adoita tratar de rexistralo e "elegantemente" termina o programa.

Hai unha variable externa chamada "errno", accesible polos programas tras incluír a biblioteca <errno.h>. O ficheiro ven da definición de posibles erros que poden ocorrer en algúns sistemas operativos cando estes solicitan recursos, coma Linux, en cuxo caso a definición está en include/asm-generic/errno.h. Esta variable indexa as descricións dos erros, accesibles pola función "strerror( errno )".

O seguinte código examina o valor a devolver pola función da biblioteca malloc para ver se a asignación dinámica de memoria se completa axeitadamente:

#include <stdio.h> // fprintf
#include <errno.h> // errno
#include <stdlib.h> // malloc, free, exit
#include <string.h> // strerror

extern int errno;

int main(void)
{

/********************************************************************
 * En referencia a carácteres, solicitude de asignación dinámica de *
 * 2.000.000.000 de elementos de almacenaxe (declarados coma un     *
 * número enteiro constante de tipo unsigned long int). (Se o teu   *
 * sistema ten menos de 2 GB de memoria dispoñibles, esta chamada   *
 * a malloc fallará.                                                *
 ********************************************************************/
	char *ptr = malloc(2000000000UL);

	if ( ptr == NULL ) // Máis adiante veremos o que son os punteiros (ptr) e como usalos axeitadamente
	puts("malloc fallou");
	else
	{
		/*********************************************************************
		 * O resto do código a partires da aquí pode asumir que se asignarán *
		 * 2.000.000.000 de carácteres satisfactoriamente... *
		 *********************************************************************/
		free(ptr); // Isto, como xa veremos máis adiante, libera a memoria reservada
	}

	exit(SAIDA_SATISFACTORIA); // Saída do programa
}

O anterior fragmento de código amosa o uso do valor devolto pola función da biblioteca malloc para buscar erros. Moitas funcións de bibliotecas devolven valores que marcan erros, e deste xeito debería ser comprobado polo astuto programador. No fragmento de código, un punteiro nulo (NULL) devolveu dos sinais de malloc un erro na asignación, polo que se saíu do programa. En implementacións máis complicadas, o programa podería tratar de manexar o erro e tratar de recuperarse da asignación de memoria fallida.

Manexo de erros ao dividir por cero

editar

Un erro habitual cometido polos programadores en C é o de non comprobar se un divisor é cero antes dun comando de división. O seguinte código produce un erro de procesamento, e a miúdo a saída do programa.

int dividend = 50;
int divisor = 0;
int quotient;
 
 quotient = (dividend/divisor); // Isto producirá un erro de execución!

Por razóns alén dos obxectivos deste capítulo (e que non se van explicar en ningún outro deste libro) debes comprobar que ningún divisor sexa nunca cero. De forma alternativa, para procesos UNIX (e baseados coma Linux), podes evitar que o sistema remate o teu proceso bloqueando a sinal SIGFPE.

O seguinte código arranxa isto comprobando o divisor antes de utilizalo na división:

#include <stdio.h> // fprintf e stderr
#include <stdlib.h> // Para a saída

int main(void)
{
	int dividend = 50;
	int divisor = 0;
	int quotient;

	if (divisor == 0) 
	{
		/***********************************************************
		 * Exemplo de manexo deste erro. Escríbeselle unha mensaxe *
		 * a stderr, e sáese cun erro. *
		 ***********************************************************/
		fprintf(stderr, "Unha división por cero! Abortando...\n");
		exit(SAIDA_ERRO); // Indica que houbo un erro
	}

	quotient = (dividend/divisor);
	exit(EXIT_SUCCESS); // Indica que todo foi ben
}