Quelle est la différence entre sscanf ou atoi pour convertir une chaîne en un entier?
gcc 4.4.4 c89
ce qui est mieux pour convertir une chaîne de caractères en une valeur entière.
j'ai essayé 2 méthodes différentes atoi et sscanf. Les deux fonctionnent comme prévu.
char digits[3] = "34";
int device_num = 0;
if(sscanf(digits, "%d", &device_num) == EOF) {
fprintf(stderr, "WARNING: Incorrect value for devicen");
return FALSE;
}
ou en utilisant atoi
device_num = atoi(digits);
je pensais que le sscanf serait mieux que vous pouvez vérifier les erreurs. Cependant, atoi ne fait aucune vérification.
6 réponses
vous avez 3 choix:
-
atoi
c'est probablement le plus rapide si vous l'utilisez dans le code de performance critique, mais il ne fait pas de rapport d'erreur. Si la chaîne ne commence pas par un entier, elle retournera 0. Si la chaîne contient de la camelote après le nombre entier, elle convertira la partie initiale et ignorera le reste. Si le nombre est trop grand pour tenir dans int
, le comportement est indéterminé.
-
sscanf
certains rapports d'erreur, et vous avez beaucoup de flexibilité pour quel type de stocker (signé/non signé des versions de char/short/int/long/long long/size_t/ptrdiff_t/intmax_t
).
la valeur de retour est le nombre de conversions qui réussissent, donc la recherche de "%d"
retournera 0 si la chaîne ne commence pas par un entier. Vous pouvez utiliser "%d%n"
pour stocker l'index du premier caractère après le nombre entier qui est lisez dans une autre variable, et vérifiez ainsi si la chaîne entière a été convertie ou s'il y a de la camelote par la suite. Cependant, comme atoi
, le comportement sur le débordement entier est non spécifié.
-
strtol
et la famille
errno
à 0 avant de faire l'appel. Les valeurs de retour sont spécifiées sur overflow et errno
sera défini. Vous pouvez choisir n'importe quel nombre de base à partir de 2 à 36, ou spécifiez 0 comme base pour auto-interpréter le début 0x
et 0
comme hex et octal, respectivement. Les choix de type pour convertir en sont signés/non signés des versions de long/long long/intmax_t
.
si vous avez besoin d'un type plus petit, vous pouvez toujours stocker le résultat dans une variable temporaire long
ou unsigned long
et vérifier vous-même le débordement.
puisque ces fonctions prennent un argument pointeur à Pointeur, vous obtenez également un pointeur à la premier caractère suivant le nombre entier converti, gratuitement, de sorte que vous pouvez dire si la chaîne entière était un nombre entier ou analyser les données suivantes dans la chaîne si nécessaire.
personnellement, je recommande la strtol
famille pour la plupart buts. Si vous faites quelque chose de rapide et sale, atoi pourrait répondre à vos besoins.
comme une mise à part, parfois je trouve que je dois analyser les nombres où conduire espace blanc, signe, etc. ne sont pas censés être acceptés. Dans ce cas, il est assez sacrément facile de rouler votre propre pour boucle, par exemple.,
for (x=0; (unsigned)*s-'0'<10; s++)
x=10*x+(*s-'0');
ou vous pouvez utiliser (pour la robustesse):
if (isdigit(*s))
x=strtol(s, &s, 10);
else /* error */
*scanf()
famille de fonctions retourner le nombre de valeurs converties. Vous devriez donc vérifier pour vous assurer que sscanf()
retourne 1 dans votre cas. EOF
est retourné pour" input failure", ce qui signifie que ssacnf()
ne retournera jamais EOF
.
pour sscanf()
, la fonction doit analyser la chaîne de format, puis décoder un entier. atoi()
n'a pas ces frais généraux. Tous les deux souffrent du problème que les valeurs hors de portée résultent dans un comportement indéfini.
vous devez utiliser les fonctions strtol()
ou strtoul()
, qui offrent une meilleure détection des erreurs et un meilleur contrôle. Ils vous font aussi savoir si la corde entière a été consommée.
Si vous voulez un int
, vous pouvez toujours utiliser strtol()
, puis vérifier la valeur retournée pour voir si elle se situe entre INT_MIN
et INT_MAX
.
To @R.. Je pense qu'il ne suffit pas de vérifier errno
pour la détection d'erreur dans l'appel strtol
.
long strtol (const char *String, char **EndPointer, int Base)
vous devrez également vérifier EndPointer
pour les erreurs.
Combinant R.. et PickBoy répond pour la brièveté
long strtol (const char *String, char **EndPointer, int Base)
// examples
strtol(s, NULL, 10);
strtol(s, &s, 10);
Lorsqu'il n'y a pas de préoccupation concernant les entrées de chaîne ou les problèmes de portée invalides, utilisez le plus simple: atoi()
sinon , la méthode avec la meilleure détection d'erreur/plage n'est ni atoi()
, ni sscanf()
.
Cette bonne réponse tous les détails prêts à l'absence de vérification d'erreur avec atoi()
et certains vérification d'erreur avec sscanf()
.
strtol()
est le plus strict fonction de conversion d'une chaîne en int
. Pourtant, il n'est qu'un début. Ci-dessous sont des exemples détaillés pour montrer l'usage approprié et donc la raison de cette réponse après le accepté un .
// Over-simplified use
int strtoi(const char *nptr) {
int i = (int) strtol(nptr, (char **)NULL, 10);
return i;
}
C'est comme atoi()
et néglige d'utiliser l'erreur de détection de caractéristiques de strtol()
.
pour utiliser pleinement strtol()
, il y a plusieurs caractéristiques à considérer:
-
détection de pas de conversion : exemples:
"xyz"
, ou""
ou"--0"
? Dans ces cas,endptr
correspondra ànptr
.char *endptr; int i = (int)strtol(nptr, &endptr, 10); if (nptr == endptr) return FAIL_NO_CONVERT;
-
la chaîne entière doit-elle être convertie ou seulement la partie principale:
"123xyz"
est-elle OK?char *endptr; int i = (int)strtol(nptr, &endptr, 10); if (*endptr != '"151920920"') return FAIL_EXTRA_JUNK;
-
Détecter si la valeur était si grand, le résultat n'est pas représentable comme un
long
comme"999999999999999999999999999999"
.errno = 0; long L = strtol(nptr, &endptr, 10); if (errno == ERANGE) return FAIL_OVERFLOW;
-
Détecter si la valeur est en dehors de la plage de
int
, mais paslong
. Siint
etlong
ont la même portée, cet essai n'est pas nécessaire.long L = strtol(nptr, &endptr, 10); if (L < INT_MIN || L > INT_MAX) return FAIL_INT_OVERFLOW;
-
certaines implémentations vont au-delà de la norme C et mettent
errno
pour des raisons supplémentaires telles que errno à EINVAL dans le cas où aucune conversion n'a été exécuté ouEINVAL
la valeur du paramètre de Base n'est pas valide. . Le meilleur moment pour tester ces valeurserrno
dépend de l'implémentation.
Mettre tous ensemble: (à Adapter à vos besoins)
#include <errno.h>
#include <stdlib.h>
int strtoi(const char *nptr, int *error_code) {
char *endptr;
errno = 0;
long i = strtol(nptr, &endptr, 10);
#if LONG_MIN < INT_MIN || LONG_MAX > INT_MAX
if (errno == ERANGE || i > INT_MAX || i < INT_MIN) {
errno = ERANGE;
i = i > 0 : INT_MAX : INT_MIN;
*error_code = FAIL_INT_OVERFLOW;
}
#else
if (errno == ERANGE) {
*error_code = FAIL_OVERFLOW;
}
#endif
else if (endptr == nptr) {
*error_code = FAIL_NO_CONVERT;
} else if (*endptr != '"151950920"') {
*error_code = FAIL_EXTRA_JUNK;
} else if (errno) {
*error_code = FAIL_IMPLEMENTATION_REASON;
}
return (int) i;
}
Note: toutes les fonctions mentionnées permettent des espaces de tête, un caractère facultatif de tête signal et sont touchés par le changement locale . Un code supplémentaire est requis pour une conversion plus restrictive.
Note: changement de titre non-OP accentuation asymétrique. Cette réponse s'applique mieux à l'original du titre "convertit une chaîne en nombre entier sscanf ou atoi"
si l'utilisateur entre 34abc et que vous le passez à atoi il retournera 34. Si vous voulez valider la valeur entrée alors vous devez utiliser isdigit sur la chaîne entrée itérativement