2009-09-27 19 views
5

Jaki jest najbezpieczniejszy i najlepszy sposób na odzyskanie długa bez znaku z łańcucha w C++?Jak uzyskać długi ciąg bez znaku?

Wiem o wielu możliwych metodach.

Najpierw konwertowane podpisane długie wzięte z atolu.

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

Oczywistym problemem jest to, co dzieje się, gdy wartość przechowywana w myStr jest większa, niż może zawierać podpisana wartość long? Co pobiera atol?

Następną możliwością jest użycie strtoul.

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

Jest to jednak nieco zbyt skomplikowane dla moich potrzeb. Chciałbym prostą funkcję, string in, unsigned long base 10 out. Ponadto obsługa błędów pozostawia wiele do życzenia.

Ostatnią możliwą możliwością jest użycie sscanf.

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

I znowu, obsługa błędów pozostawia wiele do życzenia i jest nieco bardziej skomplikowana, niż bym chciał.

Pozostałą oczywistą opcją jest napisanie własnej albo otoki wokół jednej z poprzednich możliwości lub czegoś, które przechodzi przez ciąg i ręcznie konwertuje każdą cyfrę, aż osiągnie ULONG_MAX.

Moje pytanie brzmi, jakie są inne opcje, których moje google-fu nie udało się znaleźć? Jakąkolwiek rzecz w bibliotece standardowej C++, która w czysty sposób przekształci ciąg znaków w unsigned long i wyrzuci wyjątki w przypadku niepowodzenia?

Przepraszam, jeśli to dupek, ale nie mogłem znaleźć żadnych pytań, które dokładnie pasowałyby do moich.

+0

'atol':" Jeśli poprawna wartość wykracza poza zakres reprezentowalnych wartości, zwracane są LONG_MAX lub LONG_MIN. " http://www.cplusplus.com/reference/clibrary/cstdlib/atol/ –

+0

Kilka pytań, nie jestem pewien, czy są to duplikaty: (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

Ja don nie rozumiem, co masz przeciwko strtoul. Jest to idealna funkcja do tego. Przekaż 0 dla bazy i będzie konwertować liczby z dowolnymi łańcuchami prefiksów bazowych, które odczytała twoja biblioteka C, takimi jak "0x". –

Odpowiedz

5

Jednym ze sposobów, aby to zrobić:

stringstream(str) >> ulongVariable; 
+0

Wprowadziłem pytanie, aby wyjaśnić, że pracuję z ciągami w stylu C w tym przypadku. Tak więc musiałby to być streamstream (string (myStr)) >> ulongvariable. To, co wydaje mi się nieefektywne, jest dla mnie nieefektywne:/Wolałbym, żeby było to coś czystszego i prostszego. –

+1

W rzeczywistości nie jest to konieczne, ponieważ 'std :: string' ma niejawny konstruktor, który przyjmuje ciąg znaków w stylu C jako parametr. Ten konstruktor pozwala ci napisać 'stringstream (" cokolwiek ")'. – hrnt

+0

* smack siebie * Oczywiście. Mimo to, jest rezultatem utworzenia dwóch klas - i całego zarządzania pamięcią - aby wykonać to, co powinna być w stanie wykonać prosta funkcja z pojedynczą pętlą wewnętrzną. Szkoda, że ​​czegoś takiego nie ma w standardowej bibliotece. –

5

Można użyć strtoul bez problemu. Funkcja zwraca liczbę unsigned long. Jeśli nie można wykonać konwersji, funkcja zwraca 0. Jeśli poprawna długa wartość jest poza zakresem, funkcja powrotu ULONG_MAX i zmienna globalna errno jest ustawiona na ERANGE.

+0

Poszukuje obsługi błędów stylu wyjątku, a nie stylu errno, jeśli to możliwe. –

+0

Obsługa błędów stylu wyjątku, ale brak narzutów przez klasy? Brzmi trochę paradoksowo :) –

+0

Cóż, funkcje mogą obsługiwać błędy w stylu wyjątków. Po prostu nie chcę tworzyć dwóch klas, których nie potrzebuję za każdym razem, gdy chcę zamienić długi. Wydaje się bardzo marnotrawny! –

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 o pisaniu int procedur parsera dla Mono (w C).
Generuje kod wykorzystujący typy natywne (do 32-bitowego przetwarzania 32-bitowego) i kody błędów w celu przepełnienia.

2

Jeśli możesz użyć bibliotek doładowania (www.boost.org) spojrzeć w bibliotece konwersji - to nagłówek tylko to

#include "boost/lexical_cast.hpp" 

to wszystko co musisz zrobić, to

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

Zajrzę do bibliotek doładowania, rozważałem użycie biblioteki interpretującej pythona, więc użycie boost może dobrze działać dla moich potrzeb. Byłoby miło, gdyby była to prosta funkcja czysta dla tych, którzy nie chcą uzależnienia od bibliotek boost. –

0

Solidna sposób będzie napisać funkcję statycznego i używać go

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

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

} 
+1

Przykład jest nieprawidłowy, tempptr to (char *), strtoul oczekuje (char **) – nrathaus

1

Użyj wbudowanej funkcji standardowej "atol"

Na przykład wejście std :: string = "1024";

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

Atol powinien być parametrem typu c, więc c_str() robi to za Ciebie.

Powiązane problemy