2009-09-27 15 views
5

Was ist der sicherste und beste Weg, um ein unsigned long aus einer Zeichenfolge in C++ abzurufen?Wie erhalten Sie eine Zeichenfolge ohne Vorzeichen?

Ich kenne eine Reihe von möglichen Methoden.

Zuerst konvertiert eine signierte lange aus atol genommen.

Das offensichtliche Problem damit ist, was passiert, wenn der in myStr gespeicherte Wert größer ist als eine signierte Länge enthalten kann? Was holt atol?

Die nächste Möglichkeit ist die Verwendung von strtoul.

char *myStr; // Initalized to some value somehow. 
unsigned long n = strtoul(myStr, 0, 10); 

Allerdings ist dies ein wenig zu kompliziert für meine Bedürfnisse. Ich hätte gerne eine einfache Funktion, string in, unsigned long base 10 out. Auch die Fehlerbehandlung lässt viel zu wünschen übrig.

Die letzte Möglichkeit, die ich gefunden habe, ist die Verwendung von sscanf.

Noch einmal, Fehlerbehandlung lässt viel zu wünschen übrig, und ein wenig komplizierter als ich möchte.

Die verbleibende offensichtliche Option ist, entweder einen Wrapper um eine der vorherigen Möglichkeiten oder etwas, das durch die Zeichenfolge zyklisch durchläuft, zu schreiben und jede Ziffer manuell zu konvertieren, bis sie ULONG_MAX erreicht.

Meine Frage ist, was sind die anderen Optionen, die mein Google-Fu nicht gefunden hat? Irgendeine Sache in der C++ - Standardbibliothek, die eine Zeichenfolge sauber in eine vorzeichenlose Länge konvertiert und Ausnahmen bei einem Fehler auslöst?

Ich entschuldige mich, wenn es sich um einen Betrogenen handelt, aber ich konnte keine Fragen finden, die genau mit meinen übereinstimmen.

+0

'atol':" Wenn der korrekte Wert außerhalb des Bereichs der darstellbaren Werte liegt, wird LONG_MAX oder LONG_MIN zurückgegeben. " http://www.cplusplus.com/reference/clibrary/cstdlib/atol/ –

+0

Paar Fragen, ich bin mir nicht sicher, ob es sich um Duplikate handelt: (1) http://stackoverflow.com/questions/1243428/convert- string-zu-int-mit-bool-fail-in-c/1243435 (2) http://stackoverflow.com/questions/1435253/c-syntax-question-if-var-type-int/1435268 – GManNickG

+3

ich don verstehe nicht, was du gegen strtoul hast. Es ist die perfekte Funktion dafür. Übergeben Sie eine 0 für die Basis und es konvertiert Zahlen mit beliebigen Basis-Präfix-Strings, die Ihre C-Bibliothek versteht, wie "0x". –

Antwort

5

Eine Möglichkeit, dies zu tun:

stringstream(str) >> ulongVariable; 
+0

Ich habe die Frage editiert, um deutlicher zu machen, dass ich in diesem Fall mit C-Style Strings arbeite. Also müsste dies streamstream sein (string (myStr)) >> ulongvariable. Was für mich unwirtschaftlich und ineffizient ist: Ich hätte es lieber etwas sauberer und geradliniger. –

+1

Eigentlich ist das nicht notwendig, weil 'std :: string' einen impliziten Konstruktor hat, der eine C-style-Zeichenfolge als Parameter akzeptiert. Dieser Konstruktor erlaubt es Ihnen, nur 'stringstream (" was auch immer ")' 'zu schreiben. – hrnt

+0

* smack selbst * Natürlich. Nichtsdestotrotz führt dies dazu, dass zwei Klassen - und die damit verbundene Speicherverwaltung - instanziiert werden, um das zu tun, was eine einfache Funktion mit einer einzigen internen Schleife erreichen könnte. Ich wünschte, es wäre so etwas in der Standardbibliothek eingebaut. –

5

können Sie strtoul ohne Probleme verwenden. Die Funktion gibt eine vorzeichenlose Länge zurück. Wenn die Konvertierung nicht durchgeführt werden kann, gibt die Funktion 0 zurück. Wenn der korrekte lange Wert außerhalb des Bereichs liegt, wird die Funktion ULONG_MAX und die globale Variable errno auf ERANGE gesetzt.

+0

Suche nach Exception-Style-Fehlerbehandlung statt Errno-Stil, wenn möglich. –

+0

Exception Stil Fehlerbehandlung, aber keine Overhead durch Klassen? Klingt ein bisschen paradox imo :) –

+0

Nun, Funktionen können Ausnahmefehlerbehandlung durchführen. Ich möchte einfach nicht zwei Klassen instanziieren, die ich nicht jedes Mal brauche, wenn ich eine lange konvertieren möchte. Es scheint sehr verschwenderisch! –

4
template <class T> 
T strToNum(const std::string &inputString, 
      std::ios_base &(*f)(std::ios_base&) = std::dec) 
{ 
    T t; 
    std::istringstream stringStream(inputString); 

    if ((stringStream >> f >> t).fail()) 
    { 
     throw runtime_error("Invalid conversion"); 
    } 
    return t; 
} 


// Example usage 
unsigned long ulongValue = strToNum<unsigned long>(strValue); 
int intValue    = strToNum<int>(strValue); 

int intValueFromHex  = strToNum<int>(strHexValue,std::hex); 
unsigned long ulOctValue = strToNum<unsigned long>(strOctVal, std::oct); 
1

Jeffrey Stedfast has a beautiful post über das Schreiben von Int Parser-Routinen für Mono (in C).
Er generiert Code, der native Typen verwendet (Sie benötigen 32 Bit zum Parsen von 32 Bit) und Fehlercodes für den Überlauf.

2

Wenn Sie die Boost-Bibliotheken verwenden können (www.boost.aussehen org) bei der Umwandlung Bibliothek - es ist ein Kopf nur

#include "boost/lexical_cast.hpp" 

sind dann alles, was Sie tun müssen, wird

unsigned long ul = boost::lexical_cast<unsigned long>(str); 
+0

Ich werde in die Boost-Bibliotheken schauen, ich überlegte, die Python-interpretierende Bibliothek zu verwenden, so Boost zu verwenden könnte für meine Bedürfnisse gut funktionieren. Es wäre schön, wenn es dafür eine einfache cleane Funktion gäbe, für diejenigen, die keine Abhängigkeit von den Boost-Bibliotheken wünschen. –

0

Robust Weise schreiben eine statische Funktion ist und es verwenden,

bool str2Ulong(const string& str,unsigned long & arValue) 
{ 
    char *tempptr=NULL; 
    arValue=strtoul(str,tempptr,10); 

    return ! (arValue==0 && tempptr==str.c_str()); 

} 
+1

Das Beispiel ist falsch, tempptr is (char *), strtoul erwartet (char **) – nrathaus

1

Verwenden Sie "atol" integrierte Standardfunktion

Zum Beispiel std :: string Eingabe = "1024";

std :: atol (input.c_str());

Atol erwartet, dass der Parameter vom Typ c string ist, also macht c_str() das für Sie.

Verwandte Themen