atoi — Wie erkennt man den Unterschied zwischen Null und Fehler?

Lesezeit: 4 Minuten

Benutzeravatar von Nahum
Nahum

http://www.cplusplus.com/reference/clibrary/cstdlib/atoi/

Rückgabewert

Bei Erfolg gibt die Funktion die konvertierte ganze Zahl als zurück int Wert.
Wenn keine gültige Konvertierung durchgeführt werden konnte, wird ein Nullwert zurückgegeben.
Wenn der korrekte Wert außerhalb des Bereichs darstellbarer Werte liegt, wird INT_MAX oder INT_MIN zurückgegeben.

Also, wie ich zwischen unterscheide atoi("poop") und atoi("0") und atoi("0000000")

Ja ich kann Schleife und überprüfe auf alle Nullen, falls ich ein 0-Ergebnis erhalte, aber gibt es keinen besseren Weg?

Hinweis: Ich verwende ANSI C89

  • cplusplus.com ist falsch um atoi, erkennt es überhaupt keine Fehler. Vertrauen Sie dieser Seite nicht.

    – Fred Foo

    5. März 2013 um 16:48 Uhr

  • Die Standards C89, C99 und C11 sagen nichts über den Rückgabewert von aus atoi() wenn der richtige Wert außerhalb des Bereichs liegt. Der C++11-Standard sagt sogar noch weniger (er listet atoi in zwei Tabellen, und das ist alles!). Die Aussagen von cplusplus.com sind im Wesentlichen Wunschdenken und/oder gängige Implementierungen – durch keinen Standard garantiert.

    – Jonathan Leffler

    31. August 2013 um 4:37 Uhr


  • TL;DR: Verwenden de.cppreference.com/w/cpp/string/byte/atoi stattdessen.

    – Kuba hat Monica nicht vergessen

    3. September 2015 um 16:17 Uhr

Benutzeravatar von cnicutar
Cnicutar

Das ist einer der Gründe atoi wird manchmal als unsicher angesehen. Verwenden strtol / strtoul stattdessen. Und wenn Sie es haben, verwenden Sie es strtonum.

Die Funktion atoi ist gefährlicher als man denkt. Das POSIX Standard sagt:

Wenn der Wert nicht dargestellt werden kann, ist das Verhalten undefiniert.

Der C99-Standard sagt dies auch:

7.20.1

Die Funktionen atof, atoi, atol und atoll müssen den Wert des ganzzahligen Ausdrucks errno bei einem Fehler nicht beeinflussen. Wenn der Wert des Ergebnisses nicht dargestellt werden kann, ist das Verhalten undefiniert.

  • Beantwortet nicht die Überschriftenfrage.

    – BeeOnRope

    24. November 2018 um 2:23 Uhr

  • @BeeOnRope-Bearbeitungswarteschlange ist voll. Antwort ist: “Es ist undefiniert, daher können Sie den Unterschied nicht zuverlässig bestimmen”

    – Weide

    11. Dezember 2021 um 19:03 Uhr

Benutzeravatar von Bryan P
Bryan P

Wie von @cnicutar und @ouah beschrieben, atoi kann eine gültige 0 nicht von einer ungültigen Zeichenfolge unterscheiden, die das macht strtol Familie bessere Möglichkeiten.

Aber Wieso den? und Wie? Verstehen Sie zuerst, dass beides atoi und strtol Konvertieren Sie nur die anfängliche Menge von Zahlen in einer Zeichenfolge in numerische Werte. Alle nachgestellten nicht numerischen Zeichen werden einfach ignoriert. strtol kann verwendet werden, um nach ungültigen Zeichenfolgen zu suchen, da es zusätzlich zu einem numerischen Wert auch einen Zeiger auf das Ende des numerischen Teils der Zeichenfolge zurückgibt. Also wenn das end Zeiger immer noch auf den Anfang des ursprünglichen Strings verweist, können Sie erkennen, dass ein Fehler aufgetreten ist und keine Zeichen aus dem String konvertiert wurden.

Es gibt ein paar andere Feinheiten, wie im Codebeispiel zu sehen:

long lnum;
int num;
char *end;

errno = 0;

lnum = strtol(in_str, &end, 10);        //10 specifies base-10
if (end == in_str)     //if no characters were converted these pointers are equal
    fprintf(stderr, "ERROR: can't convert string to number\n");

//If sizeof(int) == sizeof(long), we have to explicitly check for overflows
if ((lnum == LONG_MAX || lnum == LONG_MIN) && errno == ERANGE)  
    fprintf(stderr, "ERROR: number out of range for LONG\n");

//Because strtol produces a long, check for overflow
if ( (lnum > INT_MAX) || (lnum < INT_MIN) )
    fprintf(stderr, "ERROR: number out of range for INT\n");

//Finally convert the result to a plain int (if that's what you want)
num = (int) lnum;

Hinweis: Wenn Sie sicher sind, dass die Eingabezeichenfolge innerhalb des gültigen int-Bereichs liegt, können Sie sie eliminieren lnum und werfen Sie einfach die Rückkehr von strtol direkt: num = (int) strtolen(in_str, &end, 10);

  • Da ist viel Gutes dabei, aber … wenn sizeof(int) == sizeof(long), Sie haben keinen Überlauf festgestellt. Du solltest einstellen errno = 0; vor dem Anruf strtol()und dann müssen Sie testen ((lnum == LONG_MAX || lnum == LONG_MIN) && errno == ERANGE) Überlauf zu erkennen. Obwohl es funktioniert, strtol() ist eigentlich sehr schwer richtig zu verwenden – noch schwieriger als Sie demonstrieren.

    – Jonathan Leffler

    31. August 2013 um 4:29 Uhr

  • @JonathanLeffler Toller Punkt. Ich habe meine Antwort entsprechend aktualisiert, danke.

    – Bryan P

    31. August 2013 um 4:40 Uhr


  • Betreffend if ( (lnum > INT_MAX) || (lnum < INT_MIN) )für Symmetrie mit long überlaufen, das if() Block sollte auch errno = ERANGE; und setze die lnum zu INT_MAX oder INT_MIN.

    – chux – Wiedereinsetzung von Monica

    10. August 2017 um 21:55 Uhr


Benutzeravatar von ouah
ouah

Sie können nicht.

atoi kann Fehler nicht erkennen. Kann das Ergebnis nicht dargestellt werden, atoi ruft undefiniertes Verhalten auf. Verwenden strtol Anstatt von atoi.

Es wird empfohlen, eine sichere CERT-Verschlüsselung zu verwenden strtol Anstatt von atoilesen:

INT06-C. Verwenden Sie strtol() oder eine verwandte Funktion, um ein Zeichenfolgen-Token in eine ganze Zahl umzuwandeln

1410350cookie-checkatoi — Wie erkennt man den Unterschied zwischen Null und Fehler?

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

Privacy policy