2009-09-27 30 views
5

¿Cuál es la forma más segura y mejor de recuperar un largo sin firmar de una cadena en C++?¿Cómo se obtiene un largo sin firmar de una cuerda?

Conozco una serie de métodos posibles.

En primer lugar, la conversión de un largo firmado tomado de atol.

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

El problema obvio con esto es, ¿qué sucede cuando el valor almacenado en myStr es más grande que un largo firmado puede contener? ¿Qué recupera el atol?

La próxima posibilidad es usar strtoul.

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

Sin embargo, esto es un poco más complicado para mis necesidades. Me gustaría una función simple, string in, unsigned long base 10 out. Además, el manejo de errores deja mucho que desear.

La última posibilidad que he encontrado es usar sscanf.

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

Una vez más, el manejo de errores deja mucho que desear, y un poco más complicado de lo que me gustaría.

La opción obvia restante es escribir mi propia envoltura alrededor de una de las posibilidades anteriores o algo que pase por la cadena y convierta manualmente cada dígito hasta que alcance ULONG_MAX.

Mi pregunta es, ¿cuáles son las otras opciones que mi google-fu no ha podido encontrar? ¿Alguna cosa en la biblioteca estándar de C++ que convertirá limpiamente una cadena a una longitud sin signo y arrojará excepciones en caso de error?

Mis disculpas si esto es una tontería, pero no pude encontrar ninguna pregunta que coincidiera exactamente con la mía.

+0

'atol':" Si el valor correcto está fuera del rango de valores representables, se devuelve LONG_MAX o LONG_MIN ". http://www.cplusplus.com/reference/clibrary/cstdlib/atol/ –

+0

Preguntas para parejas, aunque no estoy seguro si son duplicados: (1) http://stackoverflow.com/questions/1243428/convert- string-to-int-with-bool-fail-in-c/1243435 (2) http://stackoverflow.com/questions/1435253/c-syntax-question-if-var-type-int/1435268 – GManNickG

+3

Yo don No entiendo lo que tienes contra Strtoul. Es la función perfecta para esto. Pase un 0 por la base y convertirá los números con cualquier cadena de prefijo base que su biblioteca C entienda, como "0x". –

Respuesta

5

Una forma de hacerlo:

stringstream(str) >> ulongVariable; 
+0

Edité la pregunta para dejar más claro que estoy trabajando con cadenas estilo C en este caso. Entonces esto tendría que ser streamstream (string (myStr)) >> ulongvariable. Lo cual para mí es un desperdicio ineficiente:/Preferiría que fuera algo más limpio y directo. –

+1

En realidad, eso no es necesario porque 'std :: string' tiene un constructor implícito que toma una cadena de estilo C como parámetro. Ese constructor le permite escribir simplemente 'stringstream (" whatever ")'. – hrnt

+0

* smack self * Por supuesto. Aún así, tiene el resultado de instanciar dos clases, y toda la administración de la memoria inherente en eso, para hacer lo que una función simple con un solo bucle interno debería ser capaz de lograr. Ojalá hubiera algo así en la biblioteca estándar. –

5

Usted puede utilizar strtoul sin ningún problema. La función devuelve un largo sin signo. Si no se puede realizar la conversión, la función devuelve 0. Si el valor largo correcto está fuera de rango, la función devuelve ULONG_MAX y la variable global errno se establece en ERANGE.

+0

Si es posible, busque el manejo de error de estilo de excepción en lugar del estilo errno. –

+0

Manejo de error de estilo de excepción pero sin sobrecarga por clases? Suena un poco paradoja. Imo :) –

+0

Bueno, las funciones pueden hacer un manejo de error de estilo de excepción. Simplemente no quiero instanciar dos clases que no necesito cada vez que quiero convertir una larga. ¡Parece muy derrochador! –

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 sobre writing int parser routine for Mono (in C).
Genera código que utiliza tipos nativos (necesita 32 bits para analizar 32 bits) y códigos de error para desbordamiento.

2

Si puede usar las bibliotecas de impulso (www.boost.org) mira el biblioteca de conversión - es una cabecera única incluyen

#include "boost/lexical_cast.hpp" 

entonces todo lo que necesita hacer es

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

Buscaré en las bibliotecas de impulso, estaba considerando usar la biblioteca de interpretación de python, así que usar boost podría funcionar bien para mis necesidades. Sin embargo, sería bueno si hubiera una función de limpieza simple para aquellos que no desean una dependencia en las bibliotecas de impulso. –

0

manera robusta será escribir una función estática y lo utilizan

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

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

} 
+1

El ejemplo es incorrecto, tempptr es (char *), strtoul espera (char **) – nrathaus

1

Utilice la función std incorporada "atol"

Por ejemplo std :: string input = "1024";

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

Atol espera que el parámetro sea de tipo cadena c, por lo que c_str() lo hace por usted.

Cuestiones relacionadas