gcc 4.4.4 c89
Quoi de mieux pour convertir une chaîne 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 device\n");
return FALSE;
}
ou en utilisant atoi
device_num = atoi(digits);
Je pensais que le sscanf serait mieux car vous pouvez vérifier les erreurs. Cependant, atoi ne fait aucune vérification.
Vous avez 3 choix:
atoi
C'est probablement le plus rapide si vous l'utilisez dans un code critique en termes de performances, mais cela ne génère pas de rapport d'erreur. Si la chaîne ne commence pas par un entier, elle retournera 0. Si la chaîne contient des indésirables après l'entier, elle convertira la partie initiale et ignorera le reste. Si le nombre est trop grand pour tenir dans int
, le comportement n'est pas spécifié.
sscanf
Certains rapports d’erreur, et vous avez beaucoup de flexibilité pour ce type de stockage (versions signée/non signée de char/short/int/long/long long/size_t/ptrdiff_t/intmax_t
).
La valeur renvoyée correspond au nombre de conversions réussies. Par conséquent, recherchez "%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 l'entier lu dans une autre variable et vérifier de ce fait si la chaîne entière a été convertie ou s'il y a des erreurs après. Cependant, comme atoi
, le comportement en cas de dépassement d'entier n'est pas spécifié.
strtol
et familleRapport d'erreurs robuste, à condition que vous ayez défini errno
sur 0 avant de passer l'appel. Les valeurs de retour sont spécifiées lors du débordement et errno
sera défini. Vous pouvez choisir n’importe quelle base de chiffres comprise entre 2 et 36, ou spécifier 0 comme base pour l’interprétation automatique en début de chaîne 0x
et 0
comme hex et octal, respectivement. Les choix du type de conversion sont les versions signée/non signée de long/long long/intmax_t
.
Si vous avez besoin d’un type plus petit, vous pouvez toujours stocker le résultat dans un fichier temporaire long
ou unsigned long
variable et vérifiez vous-même le débordement.
Etant donné que ces fonctions prennent un pointeur à un argument de pointeur, vous obtenez également un pointeur sur le premier caractère suivant l’entier converti, gratuitement. Vous pouvez ainsi déterminer si la chaîne entière est un entier ou analyser les données suivantes dans la chaîne si nécessaire.
Personnellement, je recommanderais la famille strtol
à des fins la plupart. Si vous faites quelque chose de rapide et sale, atoi peut répondre à vos besoins.
En passant, je trouve parfois nécessaire d'analyser les nombres lorsque les espaces, les signes, etc. ne sont pas censés être acceptés. Dans ce cas, il est très facile de lancer sa propre 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()
la famille de fonctions renvoie le nombre de valeurs converties. Donc, vous devriez vérifier que sscanf()
renvoie 1 dans votre cas. EOF
est renvoyé pour "échec d'entrée", ce qui signifie que ssacnf()
ne retournera jamais EOF
.
Pour sscanf()
, la fonction doit analyser la chaîne de formatage, puis décoder un entier. atoi()
n'a pas cette surcharge. Tous deux souffrent du problème que les valeurs hors limites entraînent un comportement indéfini.
Vous devez utiliser strtol()
ou strtoul()
, fonctions qui fournissent une détection et une vérification des erreurs bien meilleures. Ils vous ont également fait savoir si toute la chaîne avait été consommée.
Si vous voulez un int
, vous pouvez toujours utiliser strtol()
, puis vérifiez la valeur renvoyée pour voir si elle est comprise entre INT_MIN
et INT_MAX
.
Pour @R .. Je pense qu'il n'est pas suffisant de vérifier errno
pour la détection d'erreur dans strtol
call.
long strtol (const char *String, char **EndPointer, int Base)
Vous devrez également vérifier EndPointer
pour rechercher des erreurs.
Combiner R .. et PickBoy répond par souci de concision
long strtol (const char *String, char **EndPointer, int Base)
// examples
strtol(s, NULL, 10);
strtol(s, &s, 10);
Lorsqu'il n'y a aucune inquiétude concernant l'entrée de chaîne non valide ou des problèmes de plage, 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 tout prêt détaille le manque de vérification d'erreur avec atoi()
et une erreur de vérification avec sscanf()
.
strtol()
est la fonction la plus stricte pour convertir une chaîne en int
. Ce n'est pourtant qu'un début. Vous trouverez ci-dessous des exemples détaillés montrant l’utilisation correcte et la raison de cette réponse après le accepté .
// Over-simplified use
int strtoi(const char *nptr) {
int i = (int) strtol(nptr, (char **)NULL, 10);
return i;
}
Ceci est similaire à atoi()
et néglige d'utiliser les fonctions de détection d'erreur de strtol()
.
Pour utiliser pleinement strtol()
, vous devez prendre en compte plusieurs fonctionnalités:
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: Est-ce que "123xyz"
Est OK?
char *endptr;
int i = (int)strtol(nptr, &endptr, 10);
if (*endptr != '\0') return FAIL_EXTRA_JUNK;
Détecter si la valeur était si grande, le résultat ne peut pas être représenté sous forme de long
comme "999999999999999999999999999999"
.
errno = 0;
long L = strtol(nptr, &endptr, 10);
if (errno == ERANGE) return FAIL_OVERFLOW;
Détecter si la valeur était en dehors de la plage que int
, mais pas long
. Si int
et long
ont la même plage, ce test 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 définissent errno
pour des raisons supplémentaires telles que errno renvoie EINVAL si aucune conversion n'a été effectuée ou EINVAL
. La valeur de le paramètre Base n'est pas valide. . Le meilleur moment pour tester ces valeurs errno
dépend de la mise en œuvre.
Rassembler tout cela: (adaptez-vous à 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 != '\0') {
*error_code = FAIL_EXTRA_JUNK;
} else if (errno) {
*error_code = FAIL_IMPLEMENTATION_REASON;
}
return (int) i;
}
Remarque: Toutes les fonctions mentionnées autorisent les espaces et les espaces de début, un caractère facultatif et le signe , et sont affectées par locale changer. Un code supplémentaire est requis pour une conversion plus restrictive.
Remarque: le changement de titre non-OP est faussé. Cette réponse s’applique mieux au titre original "convertir une chaîne en un entier sscanf ou atoi"
Si l'utilisateur entre 34abc et que vous le transmettez à atoi, il retournera 34. Si vous souhaitez valider la valeur entrée, vous devez utiliser isdigit sur la chaîne entrée de manière itérative.