web-dev-qa-db-de.com

Das Konvertieren von Zeichenfolgen in unsigned int liefert das falsche Ergebnis

Ich habe folgende Zeichenfolge:

sThis = "2154910440";

unsigned int iStart=atoi(sThis.c_str());

Das Ergebnis ist jedoch

iStart = 2147483647

Kann jemand meinen Fehler sehen?

18
tmighty

atoi konvertiert eine Zeichenfolge in eine int. Auf Ihrem System ist eine int 32 Bit, und ihr maximaler Wert ist 2147483647. Der Wert, den Sie konvertieren möchten, liegt außerhalb dieses Bereichs, daher ist der Rückgabewert von atoi nicht definiert. Ich schätze, Ihre Implementierung gibt in diesem Fall den maximalen Wert einer int zurück.

Sie können stattdessen atoll verwenden, wodurch eine lange Länge zurückgegeben wird, die garantiert mindestens 64 Bit beträgt. Oder Sie können eine Funktion aus der Familie stoi/stol/stoll oder deren vorzeichenlose Gegenstücke verwenden, die nützliche Fehlerberichte über Werte außerhalb des Bereichs (und ungültige Werte) in Form von Ausnahmen gibt.

Persönlich mag ich boost::lexical_cast . Obwohl es etwas umständlich erscheint, kann es in einem allgemeineren Kontext verwendet werden. Sie können es in Vorlagen verwenden und das Typargument weiterleiten, anstatt Spezialisierungen zu haben

32

Verwenden Sie stattdessen std::strtoul in <cstdlib>, das für nicht vorzeichenbehaftete Nummern vorgesehen ist, einen größeren Bereich hat und Fehler besser meldet.

Wenn Sie std::string für die Eingabe und Ausnahmen für die Fehlerbehandlung verwenden möchten, verwenden Sie std::stoul. Eine kurze, hocheffiziente Implementierung sieht folgendermaßen aus:

#include <string>
#include <stdexcept>
inline unsigned int stoui(const std::string& s)
{
    unsigned long lresult = stoul(s, 0, 10);
    unsigned int result = lresult;
    if (result != lresult) throw std::out_of_range();
    return result;
}

Dies ist viel schneller als istringstream, kulturinvariant (also keine unerwarteten Änderungen des Verhaltens, wenn es in einem ungewöhnlichen Gebietsschema ausgeführt wird), vollständig portabel. Mit dem dritten Argument können Sie verschiedene numerische Basen unterstützen oder sogar die Erkennung von 0x- und 0-Präfixen durchführen .

unsigned int ist jedoch nicht unbedingt groß genug, um Ihren Wert zu speichern. Verwenden Sie unsigned long. Dann benötigen Sie den obigen Wrapper nicht.

9
Ben Voigt

atoi gibt ein vorzeichenbehaftetes int zurück, das auf Ihrer Plattform den maximalen Wert von 2^31-1 hat.

Es ist egal, was Sie dem Ergebnis zuweisen, es wird durch den Rückgabetyp begrenzt.

C++ - Streams können unsignierte Ints lesen.

std::istringstream reader(sThis);
unsigned int val;
reader >> val;
7
helloworld922

Vergessen Sie nicht, Sie können immer Ihre eigene Funktion schreiben, die genau was Sie wollen.

Dieser Code funktioniert mit einer beliebigen Zahl zwischen -9223372036854775806 (2 ^ 63 + 1) und 9223372036854775807 (2 ^ 63-1) einschließlich.

Etwas wie das:

long long int myAtoi ( string str ) {
    long long int value = 0;

    for (int i = 0; i < str.size(); i++) {

        if (str[i] != '-') {
            value *=  10;
            value += (int) ((str[i]) - '0');
        }
    }


    if (str.size() > 0 && str[0] == '-')
        return -value;
    else
        return value;
}
1
Oleksiy

Ein vorzeichenloser int ist in C++ oft ein 32-Bit-Wert, der maximal 4.294.967.295 hat. 2.154.710.440 kann daher als vorzeichenloser int dargestellt werden. Atoi wird jedoch in ein int konvertiert, das vorzeichenbehaftet ist und einen Maximalwert von 2.147.483.647 hat - also überläuft der String den Wertebereich, weshalb Ihre Antwort falsch ist. Sie können Atoll verwenden, das Ihre Zeichenfolge in eine lange Länge konvertiert, die mindestens 64 Bit beträgt. Integer-Größen sind in C++ vom Compiler abhängig. Es ist oft besser, die Header-Datei stdint.h einzuschließen und dann uint32_t oder uint64_t usw. zu verwenden, damit Sie wissen, mit welcher Größe Sie es zu tun haben.

1
David Elliman

sie können atol verwenden, der eine Zeichenfolge in long int ..__ konvertiert. Weitere Informationen finden Sie im Man atol unter Linux.

der Prototyp 

#include <stdlib.h>
long atol(const char *nptr);
1
Madan Ram

Leider hat C++ keine eingebettete Implementierung zum Parsen von unsigned int und das ist wirklich seltsam.

Hier ist ein Code, der Ihnen helfen kann:

#include <stdint.h>
#include <sstream>

inline unsigned int stoui(const std::string& s)
{
    std::istringstream reader(s);
    unsigned int val = 0;
    reader >> val;
    return val;
}

// This may be not the same as stoui on some platforms:
inline uint32_t stoui32(const std::string& s)
{
    std::istringstream reader(s);
    uint32_t val = 0;
    reader >> val;
    return val;
}
1
Sergey

Dieser Code konvertiert es mit C++ 11:

std::string sThis = "2154910440";
unsigned int iStart = static_cast<unsigned int>(std::stoul(sThis));

std::stoul gibt einen unsigned long zurück, der größer als ein unsigned int ist.

static_cast konvertiert es in den richtigen Typ.

0
GizMoCuz