Was ist der Unterschied zwischen sscanf oder atoi, um eine Zeichenfolge in eine Ganzzahl umzuwandeln?

Lesezeit: 8 Minuten

Benutzeravatar von ant2009
Ameise2009

gcc 4.4.4 c89

Was ist besser, einen String in einen Integer-Wert umzuwandeln.

Ich habe 2 verschiedene Methoden atoi und sscanf ausprobiert. Beide funktionieren wie erwartet.

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;
}

oder mit atoi

device_num = atoi(digits);

Ich dachte, dass das sscanf besser wäre, da Sie nach Fehlern suchen können. Atoi führt jedoch keine Überprüfung durch.

  • Mögliches Duplikat von Converting string to integer C

    – Ciro Santilli OurBigBook.com

    11. Mai 2016 um 18:07 Uhr

R.. GitHub STOP HELPING ICEs Benutzeravatar
R.. GitHub HÖREN SIE AUF, ICE ZU HELFEN

Sie haben 3 Möglichkeiten:

  1. atoi

Dies ist wahrscheinlich am schnellsten, wenn Sie es in leistungskritischem Code verwenden, es werden jedoch keine Fehler gemeldet. Wenn die Zeichenfolge nicht mit einer Ganzzahl beginnt, wird 0 zurückgegeben. Wenn die Zeichenfolge nach der Ganzzahl Junk enthält, wird der Anfangsteil konvertiert und der Rest ignoriert. Wenn die Zahl zu groß ist, um hineinzupassen intdas Verhalten ist nicht spezifiziert.

  1. sscanf

Einige Fehlerberichte, und Sie haben eine große Flexibilität, welchen Typ Sie speichern möchten (signierte/unsignierte Versionen von char/short/int/long/long long/size_t/ptrdiff_t/intmax_t).

Der Rückgabewert ist die Anzahl der erfolgreichen Konvertierungen, also das Scannen nach "%d" gibt 0 zurück, wenn die Zeichenfolge nicht mit einer ganzen Zahl beginnt. Sie können verwenden "%d%n" um den Index des ersten Zeichens nach der gelesenen Ganzzahl in einer anderen Variablen zu speichern und so zu prüfen, ob der gesamte String konvertiert wurde oder ob hinterher Müll vorhanden ist. Allerdings wie atoidas Verhalten bei Ganzzahlüberlauf ist nicht spezifiziert.

  1. strtol und Familie

Robuste Fehlerberichterstattung, sofern festgelegt errno auf 0, bevor Sie den Anruf tätigen. Rückgabewerte werden bei Überlauf und angegeben errno wird gesetzt. Sie können eine beliebige Zahlenbasis von 2 bis 36 auswählen oder 0 als Basis angeben, um den Zeilenabstand automatisch zu interpretieren 0x und 0 als Hex bzw. Oktal. Auswahlmöglichkeiten für den Typ, in den konvertiert werden soll, sind signierte/unsignierte Versionen von long/long long/intmax_t.

Wenn Sie einen kleineren Typ benötigen, können Sie das Ergebnis jederzeit in einer temporären Datei speichern long oder unsigned long Variable und prüfen Sie selbst auf Überlauf.

Da diese Funktionen ein Zeiger-zu-Zeiger-Argument verwenden, erhalten Sie auch kostenlos einen Zeiger auf das erste Zeichen nach der konvertierten Ganzzahl, sodass Sie feststellen können, ob die gesamte Zeichenfolge eine Ganzzahl war, oder bei Bedarf nachfolgende Daten in der Zeichenfolge analysieren.


Ich persönlich würde die empfehlen strtol Familie für die meisten Zwecke. Wenn Sie etwas schnelles und schmutziges tun, könnte atoi Ihre Anforderungen erfüllen.

Abgesehen davon muss ich manchmal Zahlen analysieren, bei denen führende Leerzeichen, Zeichen usw. nicht akzeptiert werden sollen. In diesem Fall ist es verdammt einfach, eine eigene for-Schleife zu rollen, z.

for (x=0; (unsigned)*s-'0'<10; s++) 
    x=10*x+(*s-'0');

Oder Sie können (für Robustheit) verwenden:

if (isdigit(*s))
    x=strtol(s, &s, 10);
else /* error */ 

  • Das errno in strtol ist eine implementierungsspezifische Funktion, wie in der Manpage von strtol(3) angegeben. Um korrekt zu validieren, sollten Sie endptr übergeben. Wenn **endptr nach ‘\0’ ist strtoldann wird die Zeichenfolge als Ganzes analysiert und ist gültig (oder ihre Länge ist Null).

    – Zouppen

    5. März 2014 um 21:20 Uhr

  • @Zouppen: Keine Ahnung, woher du diese Informationen hast, aber sie sind falsch. “Die Funktionen strtol, strtoll, strtoul und strtoull geben den konvertierten Wert zurück, falls vorhanden. Wenn keine Konvertierung durchgeführt werden konnte, wird Null zurückgegeben. Wenn der korrekte Wert außerhalb des Bereichs darstellbarer Werte liegt, LONG_MIN, LONG_MAX, LLONG_MIN, LLONG_MAX, ULONG_MAX oder ULLONG_MAX wird zurückgegeben (je nach Rückgabetyp und Vorzeichen des Werts, falls vorhanden), und der Wert des Makros ERANGE wird in errno gespeichert.” (C99 7.20.1.4 Absatz 8)

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    5. März 2014 um 23:39 Uhr

  • Sie haben jedoch Recht, dass Sie andere Bedingungen überprüfen müssen. Nur Überlauf ist ein “Fehler”. Das Fehlen einer Konvertierung sollte über erkannt werden endptrund wenn Sie darauf bestehen, dass die gesamte Zeichenfolge verbraucht wird, sollten Sie dies ebenfalls überprüfen.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    5. März 2014 um 23:40 Uhr

  • Damit haben Sie recht. Nur das EINVAL-Verhalten ist etwas implementierungsspezifisch.

    – Zouppen

    8. März 2014 um 11:48 Uhr

*scanf() Funktionsfamilie gibt die Anzahl der konvertierten Werte zurück. Sie sollten sich also vergewissern sscanf() gibt in Ihrem Fall 1 zurück. EOF wird für “Eingabefehler” zurückgegeben, was bedeutet, dass ssacnf() wird nie zurückkehren EOF.

Zum sscanf()muss die Funktion die Formatzeichenfolge analysieren und dann eine Ganzzahl decodieren. atoi() hat diesen Mehraufwand nicht. Beide leiden unter dem Problem, dass Werte außerhalb des Bereichs zu undefiniertem Verhalten führen.

Du solltest benutzen strtol() oder strtoul() Funktionen, die eine viel bessere Fehlererkennung und -überprüfung bieten. Sie lassen Sie auch wissen, ob die gesamte Saite verbraucht wurde.

Wenn Sie möchten intkönnen Sie immer verwenden strtol()und überprüfen Sie dann den zurückgegebenen Wert, um festzustellen, ob er dazwischen liegt INT_MIN und INT_MAX.

  • als zusätzlicher Bonus für strtol usw., wenn Sie Ihre einstellen Base zu 0 Sie erhalten eine automatische Wahl der Konvertierung von oktaler, dezimaler oder hexadezimaler Eingabe.

    – Jens Gustedt

    6. August 2010 um 6:09 Uhr

  • Ein potenzielles Problem bei der Verwendung der Basis 0 ist, dass Zeichenfolgen mit beginnen 0 wird als Basis 8 (oktal) interpretiert. Dieses Verhalten wird von sachkundigen Benutzern erwartet, aber zu viele Leute sind es nicht oktal bewusst und sind überrascht zu finden 012 wird 10 und 019 wird 1, da die Konvertierung aufgrund der nicht oktalen Ziffer 9 gestoppt wurde.

    – chux – Wiedereinsetzung von Monica

    11. Juni 2013 um 4:02 Uhr


Benutzeravatar von PickBoy
PickBoy

An @R .. Ich denke, es reicht nicht aus, um es zu überprüfen errno zur Fehlererkennung in strtol Anruf.

long strtol (const char *String, char **EndPointer, int Base)

Sie müssen auch überprüfen EndPointer für Fehler.

Kombinieren von R..- und PickBoy-Antworten der Kürze halber

long strtol (const char *String, char **EndPointer, int Base)

// examples
strtol(s, NULL, 10);
strtol(s, &s, 10);

chux – Stellt Monicas Benutzeravatar wieder her
Chux – Wiedereinsetzung von Monica

Wenn Sie keine Bedenken wegen ungültiger Zeichenfolgeneingaben oder Bereichsproblemen haben, verwenden Sie die einfachste: atoi()

Andernfalls ist das Verfahren mit der besten Fehler-/Bereichserkennung keines von beiden atoi()noch sscanf(). Diese gute Antwort enthält alle Details zum Fehlen einer Fehlerprüfung atoi() und etwas Fehlerprüfung mit sscanf().

strtol() ist die strengste Funktion beim Konvertieren einer Zeichenfolge in int. Doch es ist nur ein Anfang. Nachfolgend finden Sie detaillierte Beispiele, um die ordnungsgemäße Verwendung und damit den Grund für diese Antwort nach der akzeptierten zu zeigen.

// Over-simplified use
int strtoi(const char *nptr) {
  int i = (int) strtol(nptr, (char **)NULL, 10);
  return i; 
}

Das ist so ähnlich atoi() und es vernachlässigt, die Fehlererkennungsfunktionen von zu verwenden strtol().

Zur vollen Nutzung strtol()gibt es verschiedene Merkmale zu beachten:

  1. Erkennung von keine Konvertierung: Beispiele: "xyz"oder "" oder "--0"? In diesen Fällen, endptr wird passen nptr.

    char *endptr;
    int i = (int)strtol(nptr, &endptr, 10);
    if (nptr == endptr) return FAIL_NO_CONVERT;
    
  2. Soll der ganze String konvertiert werden oder nur der führende Teil: Is "123xyz" OK?

    char *endptr;
    int i = (int)strtol(nptr, &endptr, 10);
    if (*endptr != '\0') return FAIL_EXTRA_JUNK;
    
  3. Erkennen, ob der Wert so groß war, dass das Ergebnis nicht als darstellbar ist long wie "999999999999999999999999999999".

    errno = 0;
    long L = strtol(nptr, &endptr, 10);
    if (errno == ERANGE) return FAIL_OVERFLOW;
    
  4. Erkennen, ob der Wert außerhalb des Bereichs von als lag intaber nicht long. Wenn int und long denselben Bereich haben, ist dieser Test nicht erforderlich.

    long L = strtol(nptr, &endptr, 10);
    if (L < INT_MIN || L > INT_MAX) return FAIL_INT_OVERFLOW;
    
  5. Einige Implementierungen gehen über den C-Standard hinaus und setzen errno aus weiteren Gründen wie z errno zu EINVAL, falls keine Konvertierung durchgeführt wurde oder EINVAL Der Wert des Base-Parameters ist ungültig.. Die beste Zeit, um diese zu testen errno Werte ist implementierungsabhängig.

Alles zusammen: (An Ihre Bedürfnisse anpassen)

#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;
}

Hinweis: Alle genannten Funktionen erlauben führende Leerzeichen, ein optionaler Zeilenabstand Schild Charakter und sind davon betroffen Gebietsschema Rückgeld. Für eine restriktivere Konvertierung ist zusätzlicher Code erforderlich.


Hinweis: Nicht-OP-Titeländerung verzerrte Betonung. Diese Antwort gilt besser für den Originaltitel “convert string to integer sscanf or atoi”

Benutzeravatar von Raghuram
Raghuram

Wenn der Benutzer 34abc eingibt und Sie sie an atoi übergeben, wird 34 zurückgegeben. Wenn Sie den eingegebenen Wert validieren möchten, müssen Sie iterativ isdigit für die eingegebene Zeichenfolge verwenden

1415770cookie-checkWas ist der Unterschied zwischen sscanf oder atoi, um eine Zeichenfolge in eine Ganzzahl umzuwandeln?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy