2009-09-27 11 views
5

Qual è il modo più sicuro e migliore per recuperare un long senza segno da una stringa in C++?Come si ottiene un lungo senza segno da una stringa?

Conosco un certo numero di metodi possibili.

In primo luogo, la conversione di un lungo firmato presa da atol.

char *myStr; // Initalized to some value somehow. 
unsigned long n = ((unsigned)atol(myStr)); 

Il problema evidente con questo è, che cosa accade quando il valore memorizzato in myStr è più grande di una firma lunga può contenere? Cosa recupera atol?

La prossima possibilità è usare strtoul.

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

Tuttavia, questo è un po 'complicato per le mie esigenze. Mi piacerebbe una semplice funzione, una stringa, una base lunga senza segno 10 fuori. Inoltre, la gestione degli errori lascia molto a desiderare.

L'ultima possibilità che ho trovato è quella di usare sscanf.

char *myStr; // Initalized to some value somehow. 
unsigned long n = 0; 
if(sscanf(myStr, "%lu", n) != 1) { 
    //do some error handling 
} 

Ancora una volta, la gestione degli errori lascia molto a desiderare e un po 'più complicata di quanto mi piacerebbe.

L'opzione ovvia rimanente è scrivere da solo un wrapper attorno a una delle possibilità precedenti o qualcosa che passa attraverso la stringa e converte manualmente ogni cifra fino a raggiungere ULONG_MAX.

La mia domanda è: quali sono le altre opzioni che il mio google-fu non è riuscito a trovare? Qualunque cosa nella libreria std C++ che convertirà in modo pulito una stringa in una lunga non firmata e genererà eccezioni in caso di errore?

Mi scuso se questo è un problema, ma non ho trovato nessuna domanda che corrispondesse esattamente alla mia.

+0

'atol':" Se il valore corretto non rientra nell'intervallo di valori rappresentabili, viene restituito LONG_MAX o LONG_MIN. " http://www.cplusplus.com/reference/clibrary/cstdlib/atol/ –

+0

Domande di coppia, non sono sicuro se sono duplicati però: (1) http://stackoverflow.com/questions/1243428/convert- string-to-int-con-bool-fail-in-c/1243435 (2) http://stackoverflow.com/questions/1435253/c-syntax-question-if-var-type-int/1435268 – GManNickG

+3

I don capisco cosa hai contro strtoul. È la funzione perfetta per questo. Passa uno 0 per la base e convertirà i numeri con qualsiasi stringa di prefisso di base che la tua libreria C comprende, come "0x". –

risposta

5

Un modo per farlo:

stringstream(str) >> ulongVariable; 
+0

Ho modificato la domanda per chiarire che sto lavorando con stringhe in stile C in questo caso. Quindi questo dovrebbe essere streamstream (string (myStr)) >> ulongvariable. Il che mi sembra uno spreco inefficiente:/preferirei che fosse qualcosa di più pulito e più diretto. –

+1

In realtà, ciò non è necessario perché 'std :: string' ha un costruttore implicito che accetta una stringa in stile C come parametro. Quel costruttore ti permette di scrivere solo 'stringstream (" qualunque cosa ")'. – hrnt

+0

* smack self * Naturalmente. Anche così, ha il risultato di istanziare due classi - e tutta la gestione della memoria inerente a ciò - per fare ciò che una semplice funzione con un singolo ciclo interno dovrebbe essere in grado di realizzare. Vorrei che ci fosse qualcosa di simile nella libreria standard. –

5

È possibile utilizzare strtoul senza alcun problema. La funzione restituisce un long senza segno. Se non è possibile eseguire la conversione, la funzione restituisce 0. Se il valore lungo corretto è fuori intervallo, la funzione restituisce ULONG_MAX e la variabile globale errno è impostata su ERANGE.

+0

Ricerca della gestione degli errori dello stile di eccezione anziché dello stile errno, se possibile. –

+0

Gestione degli errori di stile eccezione, ma nessun sovraccarico attraverso le classi? Sembra un po 'paradossale :) –

+0

Bene, le funzioni possono eseguire la gestione degli errori dello stile di eccezione. Semplicemente non voglio istanziare due classi di cui non ho bisogno ogni volta che voglio convertire un lungo. Sembra molto dispendioso! –

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 sulla scrittura di routine int parser per Mono (in C).
Genera codice che utilizza tipi nativi usa (è necessario 32 bit per analizzare 32 bit) e codici di errore per l'overflow.

2

Se è possibile utilizzare le librerie boost (www.boost.org) cerca nella libreria di conversione - si tratta di un colpo di testa solo includono

#include "boost/lexical_cast.hpp" 

allora tutto quello che dovete fare è

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

Guarderò nelle librerie di boost, stavo considerando l'utilizzo della libreria di interpretazione Python, quindi l'utilizzo di boost potrebbe funzionare bene per le mie esigenze. Sarebbe bello se ci fosse una semplice funzione pulita per questo, per coloro che non vogliono una dipendenza dalle librerie di boost. –

0

modo robusto sarà scrivere una funzione statica e utilizzarlo

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

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

} 
+1

L'esempio è errato, tempptr è (char *), strtoul si aspetta (char **) – nrathaus

1

Utilizzare la funzione std incorporata "atol"

Ad esempio std :: input stringa = "1024";

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

L'atollo prevede che il parametro sia di tipo c stringa, quindi c_str() lo fa per te.

Problemi correlati