Не толкова способи за преобразуване на строки в число и обратно

Няколко начина за преобразуване на низ в число и обратно.

Много често във форума изскача един и същи въпрос - "Как да конвертирам char*/char[]/CString/string в число?" или, по-рядко, "Как да преобразувам число в char*/char[]/CString/string". В тази кратка статия ще се опитам да отговоря възможно най-подробно.

Преобразуване на низ в число

Като вход те приемат указател към низ, завършващ с нула, и връщат число, което този низ описва.atoiиatolприемат следния числов формат: [интервали][знак]цифрииatofсъответно: [интервали][знак][цифри][.числа][deE>[знак]числа] Тукинтервали- всеки интервал, табулация (\t), вертикален табулатор (\v) - те се игнорират.Знак- символ '+' или '-'. Ако не е посочено, числото се счита за положително. Числата са знаци от '0' до '9'. За число с плаваща запетая, ако няма цифри преди знака „.“, тогава трябва да се посочи поне една цифра след него. След дробната част може да се посочи експонентата, следвайки един от префиксните знаци на експонентата. Основният недостатък на тези функции е, че те не сигнализират по никакъв начин за грешка, ако такава възникне по време на анализирането на предадения низ. Под грешка имам предвид невъзможността за правилно анализиране на предадения набор от символи - несъответствие във формата му или по други причини. Следният набор от библиотечни функции, също включени в стандартната библиотека, решава този проблем:

Тези функции иматследните разлики от предишната група:

  • Чрез параметъра end_ptr те връщат указател към първия знак, който не може да се интерпретира като част от число.
  • Те контролират препълването и, ако го направи, го сигнализират, като зададат стойността на променливата errno на ERANGE и връщат съответно LONG_MAX/LONG_MIN, ULONG_MAX/ULONG_MIN и +/-HUGE_VAL, в зависимост от знака на числото в предадения низ.
  • strtodизползва информация за текущо зададените (чрез setlocale) регионални настройки, така че може правилно да интерпретира числа със символа ',' като десетичен разделител.
  • За функциитеstrtolиstrtoulможете да посочите основата на бройната система. В този случай, ако 0 се подаде като основа, тогава основата се определя автоматично от първите знаци на числото. Ако това е знакът „0“ и непосредствено последван от цифра, тогава се приема, че основата е 8. Ако първата цифра е „0“, последвана от знака „x“ или „X“, тогава се приема, че основата е 16. В други случаи основата се приема, че е 10. В този случай знаците „0“ – „9“ и „A“ – „Z“ или „a“ – „z“ могат да се използват като цифри и основата може да приема стойности от 2 до 36.
  • Ако варианти на тези функции за преобразуване на числа, описани от Unicode низове. Те се наричат ​​съответноwcstolwcstoulиwcstod.
Типична употреба на тези функции е:

КОД
char* end_ptr; long val = strtol(str, &end_ptr, 10); if (*end_ptr) // Сигнал за грешка в ред ii > // Продължаваме стандартаработа.

Както можете да видите, използването на тези функции ви дава много повече контрол върху преобразуването от низ в число. За различни трансформации препоръчвам да ги използвате. Говорейки за стандартни библиотечни функции, не може да не споменем такава функция катоscanfи нейните разновидности -sscanf,fscanfи т.н.:

и т.н. Има смисъл да използвате тази функция само когато получавате номер от потребителя от конзолата (stdin) или от файл. Трябва да се отбележи, че функцията е много тежка (от гледна точка на количеството библиотечен код, свързан с изпълнимия модул) и далеч не е толкова бърза, колкото предишните, защото за преобразуване е необходимо да се анализира форматиращият низ и да се интерпретира по съответния начин. По подобен начин можете да използвате оператори за въвеждане на поток ('>>'). В случай на писане на програми на C++, тази опция е много по-предпочитана от използването на метода scanf, тъй като осигурява много повече контрол върху типовете по време на компилиране. Очакваният числов формат може да бъде указан с помощта на флага за формат:dec -цяло число в десетичен формат;hex- цяло число в шестнадесетичен формат;oct- цяло число в осмичен формат;научно -число с плаваща запетая в експоненциален формат;фиксирано -число с плаваща запетая във fi xed format.<1 4>В този случай форматите за цели числа и числа с плаваща запетая се задават независимо един от друг. В случай на получаване на резултати от потребителско въвеждане от реда за редактиране (EditBox, CEdit), има смисъл да използвате методаGetDlgItemInt:

UINTGetDlgItemInt(HWNDhDlg,intitemId, BOOL*pTranslated, BOOLподписан) UNITCWnd::GetDlgItemInt(intitemId, BOOL*pTranslated, BOOLsigned)

Манипулаторът на диалоговия прозорец, който притежава реда за редактиране, се предава като първи параметър на извикването на API. Параметърът itemId указва идентификатора на входния низ, чрез pTranslated се връща знак, че низът, въведен от потребителя, е успешно интерпретиран като цяло число. Параметърът signed указва дали функцията трябва да върне число със знак. За да преобразувате екземпляр на класа CString в число, можете да използвате някой от предложените по-горе методи, тъй като CString лесно се преобразува в указател към низ, завършващ с нула. Разработчиците на библиотеката не предоставят специални методи за този клас. В VCL ситуацията е малко по-добра. За класа AnsiString от тази библиотека са дефинирани следните методи, които ви позволяват да получите число от неговото представяне на низ:ToInt- просто преобразуване на низ в цяло число;ToDouble- преобразува низ в число с плаваща запетая. Форматът на разделителния знак се чете от регионалните настройки на системата. И двата метода (ако низът не съответства на числовия формат) хвърлят изключение. Също така забележителен е методътToIntDef, който (ако преобразуването е неуспешно) връща стойността по подразбиране, предадена му като параметър. Тук са основните библиотечни и API функции, които могат да се използват за преобразуване на низ в число.

Преобразуване на число в низ

За съжаление няма стандартнаспециализиранафункция (описана в езиковия стандарт) за обратното преобразуване (число към низ). Но това не означава, че в RTL компилаторите няма такива функции. За преобразуване на цяло числочисла към низ, можете да използвате следните функции:

тези функции са част от библиотеката на компилатора на Microsoft. Следните функции могат да се използват за компилатори на Borland:

Както можете да видите, в компилаторите от семействата Microsoft и Borland имената на функциите не се различават много и се формират по следния принцип: [_]source_typetostring_format. Началните типове са представени със следните съкращения:i- int;l- long;ul- unsigned long;i64- int64;ui64- unsigned int 64; string format, съответно:a- one-by te char (ANSI);w- широк char (Unicode). Параметрите, приети като вход, имат следното значение. Първият параметър (стойност) е стойността, която трябва да се преобразува в низ. Вторият (низ) е буфер, където ще бъде поставен резултатът от преобразуването. А третото (radix) е основата на бройната система, в която ще бъде представено числото. Като казах по-горе, че няма стандартни функции за преобразуване на число в низ, бях малко хитър, защото имах предвид точноспециализиранифункции - аналози наatoiиstrtol. Неспециализираните стандартни функции, които извършват необходимата трансформация, включват функциятаsprintf:

който изпълнява форматиран изход към посочения буфер, както и други функции от това семейство. За преобразуването, от което се нуждаем, трябва да използваме форматиращия низ "%d". Това ще извърши стандартно преобразуване в десетично представяне на число, подобно на предишните функции. Форматът на полученото число се определя от етикета тип. Съществуват следните тагове за тип:d(илиi) - десетично цяло число със знак;u- десетично цяло число без знакo- цяло число без знак в осмичен форматx(илиX) - цяло число без знак в шестнадесетичен формат дълго със знак);h- предавано кратко цяло число (със знак/кратко без знак);l64(за Microsoft) илиL(за Borland) - предадено е 64-битово цяло число (подписано/неподписано __int64). Общо казано, когато използвате спецификатора на типа h, трябва да разберете, че променливите short (според стандарта) се повишават до тип int, когато се предават на функцията printf. По този начин този спецификатор просто казва на форматиращия да игнорира водещите битове на получения целочислен параметър. По-специално, форматиращият низ "%08x" преобразува предаденото число в низ, съдържащ шестнадесетично представяне на числото с ширина от 8 знака, докато, ако е необходимо, низът ще бъде подплатен отляво с водещи нули до 8 знака. Освен това предимството на тези функции (пред предходната група) е, че низът се преобразува в съответствие с набораза програмата(чрез извикване на функциятаsetlocale) регионални настройки (локали). Основните недостатъци на методите за форматиран изход включват ниската им скорост (с порядък по-бавна от техните специализирани аналогове), невъзможността за преобразуване в бройни системи, различни от осмична, десетична и шестнадесетична, както и липсата на контрол върху типовете и размера на прехвърления буфер, което може да доведе дотрудни за намиране грешки. Следните методи се използват за превод на числа с плаваща запетая:

- за компилатори на Microsoft и

Знакът на знака на числото се предава на последните параметри в тези функции.

Това вероятно е всичко, което може да се каже за обикновените функции за преобразуване. В следващата част ще бъдат разгледани различни опции за "самостоятелни" функции за преобразуване.

И можете да оптимизирате и обобщавате функции като _itow, _ltow, _ultow, _i64tow, _ui64tow и техните ANSI аналогове. Освен това следната функция ще работи много по-бързо от стандартните. Например, за да преобразувате цяло число в низов параметър на UNICODE, всички аналози с префикс _w първо създават char буфер с фиксиран размер, след това извикват версиите на C-низ със същото име, които извикват xtoa или x64toa, след което извикват функциите за преобразуване за преобразуване на ANSI в UNICODE (mbstowcs и __mbstowcs_mt). Тази функция не прави индиректни повиквания и отнема по-малко време, за да премине през тялото си. Prius има още една разлика от стандарта, при преобразуване в шестнадесетично число към низа се добавя префиксът "\0x".

// Следните константи трябва да се използват по време на извикването на функцията. enum Radix BINARY = 2, OCTOPLE = 8, DECIMAL = 10, HEXADEMICAL = 16 >;

шаблон void APIENTRY itos(Int val, Str buf, UINT размер, Radix r=DECIMAL) throw() Str offset = buf; // указател към низ Str first = offset; // указател към // първата цифра UINT delta_y; // стойността на цифра UINT count = 0; // брой цифри // в низа

// val е отрицателна, така че нека добавим '-' към // началото на низа. ако (стойност 0 && размер-- >= 0) delta_y = (Int)(вал % r); val /= r;

ако (delta_y> 9) // Шестнадесетичният формат. *офсет++ = (delta_y - 10 + 'a'); друго // Двоични, двоични и октопични формати. *офсет++ = (delta_y + '0'); брой++; >

// Посочва последната цифра. *офсет-- = '\0';

// Сега нашият низ съответства на целите // цифри, но е в обратен ред. Така че направете // обратната му трансформация. Ако има // само два знака, просто ги разменете без // допълнителни действия. ако (брой == 1) връщане; друго ако (брой == 2) char temp = (char)*offset; *отместване-- = *първо; *първи++ = темп; > // За повече от два символа в низа // обръщане на целия низ в следващия цикъл. друго delta_y = брой / 2;

докато (delta_y--) char temp = (char)*първо; *първо++ = *отместване; *отместване-- = температура; > > > >

Използването на ф-ии "пощи" не се отличава от стандартните.

Мисля, че този начин също има право на живота:

шаблон std::string toString(T val) std::ostringstream oss; oss T fromString(const std::string& s) std::istringstream iss(s); T res; ис >> res; връщане res; >

// Пример за използване std::string str; int iVal; float fVal;

str = toString(iVal); str = tiString(fVal);

iVal = fromString (str); fVal = fromString (str);