J'utilise un appel système et en cas d'échec, je dois faire différentes choses pour différents errnos.
J'ai besoin d'écrire du code qui ressemble à ceci:
int res;
res = systemCall();
if (res == -1)
{
if (errno == ENOMSG)
{
doSomething();
}
else
{
doSomethingElse();
}
}
perror n'aide pas, car il imprime uniquement la valeur.
En ce qui concerne strerro - si c'est ce dont j'ai besoin, je ne sais pas comment l'utiliser, car ici il dit que la chaîne réelle n'est pas la même que l'erreur. Citation de la page de manuel: "(Par exemple, si errnum est EINVAL, la description retournée sera" Argument invalide ")".
J'utilise Linux. Appels système: msgsend et msgrcv ( https://linux.die.net/man/2/msgrcv ). Je ne sais pas de quelles bibliothèques C vous parlez.
Je vois que je ne m'explique pas bien.
La déclaration est-elle valable (errno == ENOMSG)? Existe-t-il une telle variable errno? Fondamentalement, ma question est la suivante: que doit contenir l'instruction if
pour tester l'errno?
Je suppose que vous utilisez Linux et je suppose que vous n'utilisez pas directement l'appel système, mais certains des wrappers (simples) (de votre Bibliothèque C) répertoriée dans syscalls (2) . Notez que certains appels système étranges ne sont pas encapsulés par la bibliothèque C (un exemple bien connu d'appel système non encapsulé serait sigreturn (2) que vous ne devriez probablement jamais utiliser). Assez souvent, la bibliothèque C est GNU glibc , mais cela peut être musl-libc etc. Notez également que les appels système bruts du noyau ont différents conventions d'appel que la fonction C ordinaire (donc en pratique un wrapper libc est requis, et est en charge de traiter avec errno
). Notez également que errno (3) est généralement une macro (se comportant presque comme une variable).
La page de manuel msgrcv (2) indique que errno
pourrait être l'un de E2BIG
, EACCES
, EFAULT
... ENOMSG
, ENOSYS
... (reportez-vous à cette page de manuel pour obtenir la liste de toutes les erreurs possibles).
Donc, vous coderiez quelque chose comme
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);
};
};
L'instruction
if (errno == ENOMSG)
.... est-elle valide?
Oui, ça l'est; vous souhaitez tester errno
uniquement après un échec d'appel système (par exemple lorsque siz<0
).
Existe-t-il une telle variable
errno
?
Plus maintenant. Veuillez lire attentivement la documentation errno (3) . Vous ne devez pas déclarer extern int errno;
(C'était possible dans les années 80, pas en 21st siècle) mais vous devriez toujours #include <errno.h>
et utiliser errno
comme si c'était une variable, mais c'est presque toujours une macro (dont la définition apparaît dans /usr/include/bits/errno.h
qui est inclus par /usr/include/errno.h
).
BTW, les installations de style SysV ont tendance à devenir obsolètes et ne sont pas toujours disponibles. Je recommande d'utiliser les installations de files d'attente de messages POSIX, lisez mq_overview (7) .
Vous voudrez peut-être lire le programme de téléchargement gratuit Advanced Linux Programming (un vieux livre; vous pouvez acheter quelque chose de mieux et de plus récent) et/ou toutes les pages de manuel accessibles depuis intro (2) & syscalls (2) & intro (3) .
Comment vérifier la valeur de errno
:
#include <errno.h>
.if(errno == ENOENT) { ... }
, et c'est la manière courante et recommandée de le faire.errno
pour déterminer qu'une erreur s'est produite. Vérifiez la valeur de retour de la fonction et si la valeur de retour indique une erreur, vérifiez errno
pour voir quelle était l'erreur. (Plus d'informations ci-dessous.)errno
ressemble à une variable, mais ce n'est pas le cas. Cela ne vous concerne pas tant que vous dites simplement des choses comme if(errno == ENOENT) { ... }
. Mais vous ne devriez probablement pas essayer de faire quelque chose comme int errno_ptr = &errno;
.perror()
et strerror()
pour obtenir des chaînes d'erreur lisibles par l'homme correspondant aux valeurs de errno
. Mais, oui, les chaînes que vous obtenez sont généralement des choses comme "Aucun fichier ou répertoire". Je ne connais aucun bon moyen de convertir la valeur errno ENOENT
en la chaîne "ENOENT"
.Pour en dire un peu plus sur # 3. Parfois, il est tentant de dire quelque chose comme
errno = 0;
printf("Hello, world!\n");
if(errno != 0) {
fprintf(stderr, "printf failed!\n");
}
Mais ne fais pas ça. Au lieu de cela,
errno = 0;
int retval = printf("Hello, world!\n");
if(retval < 0) {
fprintf(stderr, "printf failed!\n");
}
La raison en est que, quelque part dans le processus de réalisation de son travail, printf
peut avoir fait quelque chose qui a entraîné une erreur, quelque chose qui a défini errno
, mais printf
a peut-être récupéré de cette erreur et a continué à se terminer avec succès.
Il y a très peu de fonctions de bibliothèque qui sont garanties pas pour toucher errno s'il n'y a pas eu d'erreur (je pense qu'un exemple pourrait être atoi
), mais en général, c'est quelque chose il faut faire attention.
Pour en dire un peu plus sur # 4. errno
ressemble à une variable, et plus précisément, il ressemble à une variable globale. Mais bien sûr, les variables globales sont mauvaises. Mais errno
existe depuis toujours; il y a des dizaines de millions de lignes de code qui l'utilisent; c'est toujours assez pratique; il est trop tard pour le "réparer". Donc, à la place, si vous regardez derrière le rideau, vous constaterez que la plupart des implémentations font quelque chose comme
extern int __errno_pointer;
#define errno (*__errno_pointer)
ou
extern int *__errno_pointer_function();
#define errno (*__errno_function())
De cette façon, ils peuvent faire en sorte que errno
fonctionne raisonnablement correctement même dans, disons, du code multithread.
Inclure errno.h
Quelques exemples:
// 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 */
Votre implémentation peut comporter plusieurs erreurs, comme par exemple /usr/include/asm-generic/errno.h
.