2012-07-10 18 views
9

En el caso habitual open() devuelva el nuevo descriptor de archivo, o -1 si se produjo un error y en ese caso, errno se ha configurado correctamente.¿Por qué fopen() o open() usan errno en lugar de solo devolver el código de error?

No entiendo por qué se usa este mecanismo de errno aquí? ¿Cuál es el propósito de aquí? ¿Por qué simplemente no podemos mapear todos los errores con un retorno negativo no?

como

fd = open("/dev/tty0", O_RDWR | O_SYNC); 
if(fd == -1) 
    printf("this is EACCES error"); 
else if (fd == -2) 
    printf("this is EPERM error"); 

¿Hay algún beneficio de un mecanismo de errno.? en caso afirmativo, entonces me gustaría saber/entender, entonces en otras cosas también puedo usar este mecanismo.

Respuesta

11

Desde fopen devuelve un FILE* se no puede esperar que devuelva un código de error en ese puntero: el único valor "especial" para los punteros es 0.

Como observa, para open esta restricción no se cumple. De hecho, los sistemas como Linux hacen exactamente lo que usted propone en sus niveles más bajos. La llamada al sistema debajo del capó devuelve el código de error negativo si las cosas van mal. Ese código (negado) se conecta a errno mediante un contenedor de espacio de usuario poco profundo que luego devuelve el -1 para indicar el error a la aplicación.

La razón por la que esto se hace es puramente histórico.En los viejos tiempos no había subprocesos y errno era solo una simple variable global. En ese momento, la estrategia elegida no generó demasiados gastos generales y probablemente parecía una forma aceptable de comunicarse entre el sistema operativo y la aplicación. Dado que tales interfaces básicamente no se pueden cambiar sin romper un montón de código, nos quedaremos atrapados con errno como una pseudovariable que es local de subprocesos.

Esto no es ideal, pero la sobrecarga no es tan mala como suena, ya que claramente son error indicaciones que deberían darse solo excepcionalmente.

+0

+1 muy buena respuesta –

1

errno es un código de error. Es importante asignar los errores a lo que realmente está sucediendo para que pueda tomar decisiones estratégicas en su código sobre qué hacer a continuación. Por ejemplo, ERANGE que se define en errno.h, le dirá que el resultado de strtol("0xfffffffff",NULL,0) está fuera del rango de esa función. Lo que es más importante en su ejemplo, es bueno saber si tiene un error EACCES o EPERM para saber cómo manejar el archivo.

No puede asignar todos los problemas con un código de error ya que podría tener varios problemas que le gustaría detectar y manejar. Cuando digo catch, no me refiero a try/catch.

El uso de errno establece y el mecanismo de manejo de errores para que obtenga más información que solo -1.

ERANGE, EACCES, EPERM y otros se consideran macros que se correlacionan con un número de error particular por motivos de conveniencia.

9

Para mí la ventaja es que conseguir la información de error se unifica de esa manera, volviendo algún valor negativo funcionaría bien con open ya que devuelve un entero, pero fopen devuelve una FILE * así otra técnica tendría que ser utilizado allí.

+0

ARCHIVO * sigue siendo un puntero a algún búfer/memoria, por lo que nunca será negativo, por lo que si se produjo un error, ¿no devolvemos ARCHIVO * con un valor negativo? porque NULL es 0 –

+6

Un puntero tiene, al menos en las arquitecturas que conozco, ningún concepto de firma, puede (teóricamente) cubrir todo el rango del "entero subyacente sin signo" (es decir, un punto de 32 bits puede ir de 0x00000000 a 0xffffffff) . Y 'NULL' es justo y una indicación para decir" hey, esto falló, mira a errno para ver qué salió mal " – fvu

+0

En teoría, un conjunto de punteros reservados podría usarse también; todo lo que se necesita es 'char err_ptrs [MAX_ERRNO]; void * EACCESS_ptr = err_ptrs + EACCESS; 'etc. para hacer de' EACCESS_ptr' un "código de error" válido para los punteros. Sin embargo, tener que duplicarlos como enteros y punteros, y el hecho de que algunas interfaces usan todo el espacio de valores enteros como retornos válidos, hace que errno valga la pena. –

1

Proporcionar a cada función un conjunto distinto de valores de retorno hace que sea demasiado complicado escribir código de forma genérica. Con la semántica actuales, se puede adoptar un patrón universal:

int fd; 
if ((fd = some_function(arg1, arg2)) == -1) 
{ 
    perror("some_function"); 
    exit(1); 
} 

Usted puede incluso terminar con esto en una macro:

#define CALL_OR_DIE(function, ret, ...)  \ 
    if ((ret = function(__VA_ARGS__)) == -1) \ 
    { perror(#function); exit(1); } 

Uso:

int fd; 
CALL_OR_DIE(open, fd, "/dev/tty0", O_RDWR | O_SYNC); 
+1

Así que básicamente estás diciendo (1) que es mejor escribir '== -1' que' <0' (con errnos definidos como negativos), y (2) ¿esta es la motivación para 'errno'? Supongo que hay un beneficio en no tener que pasar 'fd' a' perror' en el caso de falla, porque se puede leer desde el 'local' local' errno', pero no creo que explique por qué el errno isn 't devuelto de' abierto 'también. –

Cuestiones relacionadas