En fait il faut un peu plus de boulot :
- l'intérêt d'utiliser strtoll est d'avoir un résultat en long long qui a une taille surpéerieure à un simple int ce qui te permet de détecter facilement les over/underflows. Le cast de ton code pourrait te réserver des surprises.
- il suffit de suivre ce qui est écrit sur la man page (sans vouloir faire un RTFM ...) pour savoir si une chaîne contient exactement un entier
If endptr is not NULL, strtol() stores the address of the first invalid character in *endptr. If there were no digits at all, strtol() stores the original value of nptr in *endptr (and returns 0).
In particular, if *nptr is not '\0' but **endptr is '\0' on return, the entire string is valid.
Si tu décides de créer une fonction de validation, tu pourrais par exemple créer des codes qui vont préciser si l'opération s'est bien déroulée ou quelle est la cause de l'erreur :
typedef enum {CONV_OK=0, CONV_ERR_RANGE=1, CONV_ERR_EXTRACHAR=2, CONV_ERR_NODIGITS=4, CONV_ERR_EMPTY=8, CONV_ERR=15} conv_status_t
où
- CONV_OK signale que tout s'est bien passé, la chaîne ne contenait qu'un entier valide et rien d'autre
- CONV_ERR_RANGE signale une erreur d'over/undeflow : on a bien reconnu un entier mais il n'est pas codable sur un int
- CONV_ERR_EXTRACHAR signale qu'on a réussi à trouver un entier mais qu'il reste des caractères à traiter qui ne sont pas des chiffres
- CONV_ERR_NO_DIGITS signale que la chaîne ne commençait même pas par un entier
- CONV_ERR_EMPTY signale que la chaîne à traiter était soit vide soit NULL.
Tu peux alors imaginer une fonction comme :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| conv_status_t convert_to_int (const char *str, int *presult) {
*presult=0;
if ( (str==NULL) || (*str==0) ) {
return CONV_ERR_EMPTY;
} else {
char *endptr;
long long int tmp=strtoll (str, &endprt, 10);
if (*endptr==0) {
if ( (tmp>INT_MAX) || (tmp<INT_MIN) ) {
return CONV_ERR_RANGE;
} else {
*presult = (int) tmp;
return CONV_OK;
}
} else if (endptr==str) {
return CONV_ERR_NODIGITS;
} else {
return CONV_ERR_EXTRACHAR;
}
}
} |
J'ai tapé cette fonction à la volée et je ne l'ai pas testée. Il s'agit donc plus d'une idée dont tu peux t'inspirer que d'un code à copier/coller.
Dans ton cas de figure, tu ne devrais jamais tomber sur un cas CONV_ERR_EMPTY si tu vérifies le nombre d'arguments passés à l’exécution. Il n'est pas nécessaire de vérifier errno car même en cas d'over/undeflow sur un long long l'over/underflow sera correctement traité, et comme tu choisis une base fixe (en l'occurence 10), on ne pourra jamais avoir un EINVAL.
Partager