
hana
Estoy usando una llamada al sistema y, en caso de que falle, necesito hacer cosas diferentes para diferentes errnos.
Necesito escribir un código que se vea así:
int res;
res = systemCall();
if (res == -1)
{
if (errno == ENOMSG)
{
doSomething();
}
else
{
doSomethingElse();
}
}
perror no ayuda, porque solo imprime el valor.
En cuanto a strerro, si es lo que necesito, no estoy seguro de cómo usarlo, porque aquí dice que la cadena real no es la misma que el error. Cita de la página del manual: “(Por ejemplo, si errnum es EINVAL, la descripción devuelta será “Argumento no válido”)”.
Estoy usando Linux. Llamadas al sistema: msgsend y msgrcv (https://linux.die.net/man/2/msgrcv). No estoy seguro de qué bibliotecas C está preguntando.
Veo que no me expliqué bien.
¿Es válida la afirmación if (errno == ENOMSG)? ¿Existe tal variable errno? Básicamente mi pregunta es: ¿Qué debe ir en el if
declaración para probar el errno?

steve cumbre
Cómo comprobar el valor de errno
:
- Necesitaras
#include <errno.h>
.
- Sí, definitivamente puedes decir cosas como
if(errno == ENOENT) { ... }
y esa es la forma común y recomendada de hacerlo.
- En general, haz no usar
errno
para determinar que se ha producido un error. Compruebe el valor de retorno de la función y, si el valor de retorno indica un error, compruebe errno
para ver cual fue el error. (Más sobre esto a continuación).
errno
parece una variable, pero en realidad no lo es. Esto no te concierne mientras digas cosas como if(errno == ENOENT) { ... }
. Pero probablemente no deberías intentar hacer algo como int errno_ptr = &errno;
.
- Puedes usar funciones como
perror()
y strerror()
para obtener cadenas de error legibles por humanos correspondientes a errno
valores. Pero, sí, las cadenas que obtienes son generalmente cosas como “No existe tal archivo o directorio”. No hay una buena manera que yo sepa para convertir el valor errno ENOENT
a la cuerda "ENOENT"
. (Anexo: consulte esta pregunta para obtener algunas respuestas).
Para decir un poco más sobre el #3. A veces es tentador decir algo como
errno = 0;
printf("Hello, world!\n");
if(errno != 0) {
fprintf(stderr, "printf failed!\n");
}
Pero no hagas eso. en lugar de hacer
int retval = printf("Hello, world!\n");
if(retval < 0) {
fprintf(stderr, "printf failed!\n");
}
La razón es que, en algún momento del proceso de hacer su trabajo, printf
podría haber hecho algo que resultó en un error, algo que estableció errno
pero printf
podría haberse recuperado de ese error y continuar hasta completarse con éxito.
Hay muy pocas funciones de biblioteca que están garantizadas no tocar errno si no hubo un error (creo que un ejemplo podría ser atoi
), pero en general, esto es algo con lo que hay que tener cuidado.
Para decir un poco más sobre el #4. errno
parece una variable, y más específicamente, parece una variable global. Pero, por supuesto, las variables globales son malas. Pero errno
ha existido desde siempre; hay decenas de millones de líneas de código que lo utilizan; sigue siendo básicamente bastante conveniente; es demasiado tarde para “arreglarlo”. Entonces, en cambio, si mira detrás de la cortina, encontrará que la mayoría de las implementaciones hacen algo como
extern int __errno_pointer;
#define errno (*__errno_pointer)
o
extern int *__errno_pointer_function();
#define errno (*__errno_function())
De esta manera, pueden organizar errno
para que funcione razonablemente bien incluso en, digamos, código multihilo.

Basile Starynkevitch
Supongo que estás usando Linux, y supongo que no directamente use la llamada al sistema, pero algunos de los contenedores (simples) (de su biblioteca C) enumerados en llamadas al sistema(2). Tenga en cuenta que algunas llamadas extrañas al sistema no están empaquetadas por la biblioteca C (un ejemplo bien conocido de llamada al sistema sin empaquetar sería sigreturn(2) que probablemente nunca deberías usar). Muy a menudo, la biblioteca C es GNU glibcpero podría ser Musl-libc etc. Tenga en cuenta también que las llamadas al sistema sin procesar del núcleo tienen diferentes convenciones de llamadas que la función C ordinaria (por lo que en la práctica se requiere un envoltorio libc, y está a cargo de tratar con errno
). Note también que error(3) es generalmente una macro (casi se comporta como una variable).
Él msgrcv(2) documentos de página man que errno
podría ser uno de E2BIG
, EACCES
, EFAULT
… ENOMSG
, ENOSYS
… (consulte esa página del manual para obtener la lista de todos los posibles errores).
Entonces codificarías algo como
ssize_t siz = msgrcv(msqid, msgp, msgsz, msgtyp, msgflg);
if (siz<0) { // msgrcv failed and has set errno
if (errno == ENOMSG)
dosomething();
else if (errno == EAGAIN)
dosomethingelse();
/// etc
else {
syslog(LOG_DAEMON|LOG_ERR, "msgrcv failure with %s\n",
strerror(errno));
exit(EXIT_FAILURE);
};
};
es la declaración if (errno == ENOMSG)
…. ¿válido?
Sí, lo es; quieres probar errno
solo después de alguna falla en la llamada al sistema (por ejemplo, cuando siz<0
).
¿Existe tal variable? errno
?
Ya no. Por favor lea cuidadosamente error(3) documentación. no debes declarar extern int errno;
(esto era posible en la década de 1980, no en 21S t siglo) pero deberías siempre #include <errno.h>
y use errno
como si fuera una variable, pero casi siempre es alguna macro (cuya definición aparece en /usr/include/bits/errno.h
que está incluido por /usr/include/errno.h
).
Por cierto, las instalaciones de estilo SysV tienden a volverse obsoletas y no siempre están disponibles. Recomiendo usar las instalaciones de colas de mensajes POSIX, lea mq_resumen(7).
Es posible que desee leer el descargable gratuito Programación avanzada de Linux (un libro antiguo; puede comprar algo mejor y más nuevo) y/o todas las páginas man accesibles desde introducción(2) & llamadas al sistema(2) & introducción(3).

0___________
Incluir errno.h
Algunos ejemplos:
// Error codes
#define EPERM 1 /* Operation not permitted */
#define ENOENT 2 /* No such file or directory */
#define ESRCH 3 /* No such process */
#define EINTR 4 /* Interrupted system call */
#define EIO 5 /* I/O error */
#define ENXIO 6 /* No such device or address */
#define E2BIG 7 /* Argument list too long */
#define ENOEXEC 8 /* Exec format error */
#define EBADF 9 /* Bad file number */
#define ECHILD 10 /* No child processes */
#define EAGAIN 11 /* Try again */
#define ENOMEM 12 /* Out of memory */
#define EACCES 13 /* Permission denied */
#define EFAULT 14 /* Bad address */
#define ENOTBLK 15 /* Block device required */
#define EBUSY 16 /* Device or resource busy */
#define EEXIST 17 /* File exists */
#define EXDEV 18 /* Cross-device link */
#define ENODEV 19 /* No such device */
#define ENOTDIR 20 /* Not a directory */
#define EISDIR 21 /* Is a directory */
#define EINVAL 22 /* Invalid argument */
#define ENFILE 23 /* File table overflow */
#define EMFILE 24 /* Too many open files */
#define ENOTTY 25 /* Not a typewriter */
#define ETXTBSY 26 /* Text file busy */
#define EFBIG 27 /* File too large */
#define ENOSPC 28 /* No space left on device */
#define ESPIPE 29 /* Illegal seek */
#define EROFS 30 /* Read-only file system */
#define EMLINK 31 /* Too many links */
#define EPIPE 32 /* Broken pipe */
#define EDOM 33 /* Math argument out of domain of func */
#define ERANGE 34 /* Math result not representable */
Su implementación puede tener más errno incluidos, como por ejemplo /usr/include/asm-generic/errno.h
.
¿En qué sistema operativo? ¿Qué llamada del sistema exacta? ¿Qué biblioteca C? Por favor edita tu pregunta para mejorarla
– Basile Starynkevitch
02/09/2017 a las 11:51
Cada llamada al sistema tiene una lista de posibles valores de errno (vea su
man
página), esto le permitirá saber contra qué debe realizar la prueba.– mística
2 de septiembre de 2017 a las 11:58
Lo que has escrito está bien. Recuerde, no hay conjuntos de funciones de biblioteca
errno
a cero, y no debe probarlo a menos que una función indique un error y esté documentada para establecererrno
. Tenga en cuenta que muchas funciones de pthreads no se configuranerrno
, por ejemplo; en su lugar, devuelven el número de error. Además, las funciones pueden establecererrno
a un valor distinto de cero incluso si tiene éxito. Por ejemplo, en Solaris, si la salida estándar no es un terminal,errno
se puede establecer en ENOTTY aunque elprintf()
la llamada es exitosa.–Jonathan Leffler
02/09/2017 a las 12:30