Programátoři, kteří s jazykem C (C++) teprve začínají, mohou mít problémy s konverzemi z řetězce na číslo (a zpět z čísla na řetězec). Cílem tohoto článku je poskytnout těmto programátorům přehled metod, jak v C/C++ tyto konverze snadno a bez úrazů provést. Pro ostřílené profesionály tento článek nebude ničím novým, můžete jej klidně přeskočit.
K převodům z řetězce na číslo můžeme použít buďto vestavěné funkce jazyka C, nebo ve speciálních případech i API funkce systému Windows. Před konverzí z řetězce na číslo je nutné si jenom uvědomit, jaké číslo chceme z řetězce získat (celé, desetinné).
Nejjednoduššími funkcemi jazyka C pro konverzi řetězce na číslo jsou funkce atoi(), atol(), atof(), atold() a pro 64-bitové hodnoty funkce _atoi64(). Použití těchto funkcí shrnuje následující tabulka:
atoi() | atol() | |
---|---|---|
Návratová hodnota | int | long |
Příklad použití |
char * szNum = "12345678"; int iNum = atoi(szNum); printf("atoi() : %i\n", iNum); |
char * szNum = "12345678"; long iNum = atol(szNum); printf("atol() : %ld\n", iNum); |
atof() | _atoi64() | |
---|---|---|
Návratová hodnota | double | __int64 |
Příklad použití |
char * szNum = "12345789123456789"; __int64 iNum = _atoi64(szNum); printf("_atoi64() : %I64i\n", iNum); |
char * szNum = "12345.678"; double fNum = atof(szNum); printf("atof() : %f\n", fNum); |
Při použití některé z těchto funkcí je potřeba zvolit funkci s vhodnou návratovou hodnotou. Problém nastane v případě, pokud potřebujeme zjistit, zda řetězec byl v pořádku zkonvertován. Funkce totiž nevracejí chybu. V případě že se konverze podařila jen částečně, funkce vrátí to, co se podařilo zkonvertovat. V případě zcela chybného řetězce vracejí funkce nulu. Nula ale může být i správná hodnota:
printf("%i\n", atoi("123AAA")); // Prints "123" printf("%i\n", atoi("AHOJ")); // Prints "0" printf("%i\n", atoi("0")); // Prints "0"
Pokud ale nepotřebujeme ověřovat správnost konverze (jsme si na 100% jisti, že řetězec bude VŽDY obsahovat číslo), je možné bez obav použít funkce atoXX().
Další možností, jak zkonvertovat řetězec na číslo, je použití funkce strtol() nebo strtod():
long strtol(const char * nptr, char ** endptr, int base); double strtod(const char * nptr, char ** endptr);
Obě funkce vracejí výsledek konverze a zároveň volajícímu předávají pozici, na které konverze skončila. Tato vlastnost je vynikající v případě, kdy konvertujeme např. datum (1.12.2001) nebo číslo verze programu z textu do číselné podoby. Celočíselná verze (strtol) navíc umožňuje konvertovat řetězce v libovolné číselné soustavě (dvojkové, desítkové, šestnáctkové, nebo třeba v jedenáctkové - i když nepředpokládám, že byste tuto možnost někdy využili :-)). Mnohem častější je použití funkce pro konverzi v šestnáctkové soustavě:
char * szNum = "12FF3ACD"; int nResult; nResult = strtol(szNum, &szNum, 16); printf("strtol : 0x%08lX\n", nResult);
Tato funkce bohužel chybně zpracovává hodnoty vyšší než 0x7FFFFFFF. Pokud se pokusíte zpracovat řetězec např. 0xA0000000, funkce vrátí hodnotu 0x7FFFFFFF. Odstranění tohoto problému je možné napsáním vlastní funkce na konverzi:
int StrToInt(const char * ptr, char ** end, int root) { int nDigit; int acc = 0; while((nDigit = *ptr) != 0) { // If the character is not an alphanumeric, break if(!isalnum(nDigit)) break; // Convert to digit nDigit -= '0'; if(nDigit > 9) nDigit -= ('A' - '9' - 1); if(nDigit > root-1) break; // Move the value to the next rank and add the digit acc *= root; acc += nDigit; ptr++; } if(end != NULL) *end = (char *)ptr; return acc; }
Řetězce na číslo je možné převést také funkcí sscanf():
char * szNumber = "12345678"; int nNumber; sscanf(szNumber, "%i", &nNumber); printf("sscanf() : %i\n", nNumber);
Převést řetězec na číslo umí funkce StrToIntEx(), která je součástí API MS Internet Exploreru verze 4.0. Tato funkce umožňuje konvertovat i čísla v šestnáctkové soustavě. Funkce vrací FALSE, pokud se konverze nezdařila. Pokud nevadí požadavek na přítomnost Internet Exploreru 4.0 nebo vyššího (k programu je nutné přilinkovat knihovnu Shlwapi.dll, což mi přijde zbytečné na to, abychom pouze zkonvertovali řetězec na číslo), lze ji použít bez problémů:
int nResult; if(StrToIntEx("12345", STIF_DEFAULT, &nResult) == FALSE) printf("Chyba při konverzi\n");
Poslední zde uvedená možnost je konverze textu v dětském okně dialogu (editační políčko, statický text) přímo na číslo. K tomu slouží funkce GetDlgItemInt, definovaná takto:
UINT GetDlgItemInt( HWND hDlg, // Handle dialogového okna int nID, // Identifikátor dětského okna (např. IDC_EDIT1) BOOL *lpTranslated, // Ukazatel na výsledek konverze BOOL bSigned); // TRUE pokud je hodnota se znaménkem
Funkce umí zkonvertovat jak čísla se znaménkem (signed), tak i bez znaménka (unsigned), podle hodnoty parametru bSigned. Návratovou hodnotou funkce je výsledek konverze. Pokud nemohl být obsah editačního políčka zkonvertován, funkce uloží hodnotu FALSE do lpTranslated.
K převodu "opačným směrem", tedy čísla na řetězce je v jazyce C/C++ rovněž k dispozici škála funkcí, jednat vestavěných (podle normy ANSI C) a jednak i funkcí Windows API. Začneme tou asi nejznámější, sprintf().
Funkce sprintf() umí zkonvertovat jedno nebo více čísel na řetězec. K tomu, aby konverze korektně pracovala, je nutné, aby byl řetězec předem alokován (staticky, na zásobníku nebo dynamicky). Taktéž je nutné dát pozor na shodu formátovacího řetězce a typu číselné proměnné předávané jako parametr funkci sprintf:
char szNumber[20]; // Musí mít dostatečnou velikost !!! int iNumber = 12345678; double fNumber = 123.456; sprintf(szNumber, "%i", iNumber); // Správně sprintf(szNumber, "%i", fNumber); // Chyba sprintf(szNumber, "%f", iNumber); // Chyba sprintf(szNumber, "%f", fNumber); // Správně
K převodu jednoho čísla na řetězec je možné použít i funkci _itoa(). Tato funkce je pracuje obráceně k funkci atoi(), uvedené výše. Použití funkce je jednoduché, a kromě nedostatečné velikosti bufferu pro uložení textu zde nelze udělat chybu:
char szNumber[12]; int nNumber = 123456; itoa(nNumber, szNumber, 10); printf("itoa() : %s\n", szNumber);
Konverzní funkce pro desetinná čísla se jmenuje _gcvt(). Funguje obdobně jako funkce itoa(), namísto základu zadáváme počet platných číslic:
char szNumber[25]; double fNumber = 123.456; _gcvt(fNumber, 10, szNumber); // 10 = Max. 10 platných číslic printf("_gcvt() : %s\n", szNumber);
Pro účely snadného zobrazování čísel v dialogových oknech přidali vývojáři do API systému Windows funkci SetDlgItemInt(). Tato funkce je obráceným ekvivalentem funkce GetDlgItemInt(), popsané výše. Příklad na její použití je zde:
// Nastavíme hodnotu editačního políčka SetDlgItemInt(hDlg, IDC_EDIT1, 12345678, FALSE); // Nastavíme hodnotu jiného editačního políčka SetDlgItemInt(hDlg, IDC_NUM_FILES, nFiles, FALSE);
Tak, a to je vše. Převody čísel na řetězce by pro vás již neměly být problémem. Na závěr malý test - dokážete najít chyby v těchto kódech ?
//------------------------------- // Pokus č. 1 char szNumber[5]; sprintf(szNumber, "%i", 12345); //------------------------------- // Pokus č. 2 char * szNumber = "123.555"; double fValue; sscanf(szNumber, "%i", &fValue); //------------------------------- // Pokus č. 3 char * szNumber; int nValue = 1010152; itoa(nValue, szNumber, 10);
Copyright Ladislav Zezula 10.09.2003