![]() |
Модераторы: bsa |
![]() ![]() ![]() |
|
zkv |
|
||||||||||||||||||||||||
![]() ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2133 Регистрация: 23.7.2006 Где: Санкт-Петербург Репутация: нет Всего: 92 |
Преобразование переменной типа int (unsigned, float, double etc.) в char *, и обратно
С этим вопросом на начальном этапе сталкиваются практически все. Выглядит он примерно так:
Приведенный выше пример некорректен, дело в том, что автор хотел выполнить конвертацию, а сделал приведение типа int к char *. Выполнить конвертацию можно с помощью sprintf(), itoa() (язык С), std::ostringstream, boost::format (язык С++), также можно попытаться проделать это вручную. Я не буду заострять внимание на том, как использовать эти функции, умение придет с опытом, лучше попробую раскрыть суть проблемы. Способ хранения С-строк (char *) в памяти компьютера. Конвертирование вручную. Все данные в памяти хранятся в числовом выражении, будь то цифры, символы, картинки и т.д. и т.п. Различия начинаются только при выводе данных, на монитор, принтер и т.п., то есть при из визуализации. Получается компьютер не рисует у себя в памяти символы А Б В а записывает их код. Для каждого символа он узнает этот код из таблицы символов. Таблица символов представляет из себя набор пар символ<->код, каждое соотношение взаимооднозначное. Таблицу символов также часто называют кодировкой. Существует множество различных кодировок, в разных кодировках отдельный символ может представляться разным количеством бит (я, например, слышал только о 8-битных и 16-битных кодировках). Как бы то ни было, здесь мы рассматриваем только ASCII-кодировку, будем считать, что она 8-битная (и 1-байтная ![]() Итак, каждый символ в памяти - это некоторое числовое значение (код символа), узнать его можно, например, попросив компилятор рассматривать его как целое число, а не как символ:
это предотвратит подстановку визуального отображения символа вместо его кода. В арифметических операциях никаких приведений вообще не нужно, вычислим, к примеру, расстояние между символами '0' и '9' в таблице:
Строка же представляет из себя последовательность кодов символов, заканчивающихся нуль-символом: '\0' (обратный слэш информирует о начале escape-последовательности), те символом с кодом 0, этот символ нужен для определения конца строки. При формировании строки вручную, очень важно не забывать добавлять его, иначе ваша программа может начать выводить всякую бяку, может портить данные, может вообще рухнуть. В качестве примера* попробуем перевести введенное пользователем целое число в его строковое представление. Я делаю это только в демонстрационных целях, в реальных проектах лучше не привязывать себя к конкретным реализациям строк, а использовать готовые, протестированные решения. В этом примере, мы воспользуемся тем, что коды символов цифр ('0', '1', '2' и т.д.) следуют друг за другом непрерывно, и упорядоченно по возрастанию, начиная с нуля (чувствуете, как мы привязываем свое решение к конкретной таблице символов, никто не гарантирует, что это утверждение верно для всех таблиц)
Способы доступа к С-строкам. Что такое приведение типов. Доступ к С-строке осуществляется посредством указателя на ее первый символ. То есть в таком примере:
в переменной str записано число - адрес первого символа строки (буквы 'T'), другими словами str - указывает на символ 'T' строки (вернее строкового литерала*, в данном случае) The String почему-же тогда при выполнении такого кода:
компилятор выводит The String а не это число? Все просто: вывод переменных типа char * производится по специальному правилу: выводится первый символ по адресу, записанному в переменной, затем указатель "перенацеливается" на следующий символ (инкрементируется), символ выводится, и так далее, пока не встретим нуль-символ - '\0' (что означает - строка закончена). То, что пытался сделать воображаемый программист в начале топика:
называется приведением типов. В данном случае такое приведение предлагает рассматривать значение, хранящееся в переменной var как адрес некоторой строки в памяти. Понятно, что в данном участке памяти может лежать все что угодно, в результате мы можем порушить программу, либо испортить данные, но ничего даже близкого к тому, что мы хотели получить не выйдет. Конвертирование в стиле языка С. Имеем два варианта:
и
Первый вариант лучше, тем, что он стандартный (те обязан присутствовать в библиотеках любого ANSI-C компилятора), поддерживает форматированный вывод, что обеспечивает большую гибкость вывода данных, поддерживаемые форматы можно подглядеть в описании функции printf(). Пример для sprintf()***:
Функция же itoa() - не стандартная, но довольно распространенная, некоторые считает ее более удобной, хотя мне sprintf() симпатичнее ;). Но у нее есть одно преимущество: возможность представлять число при выводе в заданной системе счисления (я встречал информацию, поддерживаются основания от 2 до 32, но определенно все равно сказать ничего нельзя, по скольку стандарт насчет этой функции молчит). Ну и пример (не мудрствуя лукаво скопировал из ссылки):
Конвертирование в стиле языка С++. Начнем конечно со stringstream, конкретно в нашей задаче - ostringstream (первая буква 'o' говорит нам, что это поток вывода). Это стандартный класс для работы со строковыми потоками****, со всеми вытекающими плюсами. Пример:
Ну и остался boost::format, признаюсь, что сам с ним не работал - не возникало такой необходимости, так как вполне устраивал stringstream, по-этому за дальнейшей информацией и примерами по нему прошу в документацию. Обратная конвертация (из строки в число). Это действо можно назвать парсингом строки. Здесь используются аналогичные инструменты: sscanf() и atoi() для C, и istringstream для C++. Описывать их я не буду, примеры приводить тоже, все делается аналогично приведенным выше инструментам, так что вы справитесь с ними без труда. Примечания. *...В качестве примера... - если вы скомпилируете и запустите этот пример, то он скорее всего выполнится быстрее, чем вы сможете заметить результаты его работы, как это исправить рассказано (будет?) в другом топике в это FAQ. **...вернее строкового литерала... - не нашел подходящей ссылки с описанием, что есть строковый литерал, есть у кого на примете? ***...Пример для sprintf()... - а в этом примере неправильно будут отображаться русские буквы в консоли, что делать - описано (будет?) в соседнем топике ****...класс для работы со строковыми потоками... - в данной ссылке описан класс strstream который считается устаревшим и нерекомендован к использованию. ________________________________________________________________________________ Прилагаю "исходник" статьи, если кто-то хочет предложить свой вариант. (FireFox обзывает кодировку приложенного файла "Кириллица (Windows-1251)") Да, если нетрудно, то плиз покажите места, где текст труднодоступный, буду переформулировать по возможности. Здесь, кстати, больше интересует мнение неискушенных в вопросе программистов. Назад к FAQ Это сообщение отредактировал(а) bsa - 26.7.2011, 11:03 Присоединённый файл ( Кол-во скачиваний: 60 ) ![]() |
||||||||||||||||||||||||
|
|||||||||||||||||||||||||
Fazil6 |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 7 Всего: 60 |
парни, вы разве факов раньше не видели? Обычно открыв фак имеешь по 2-3 вопроса с ответами на странице. Ну не нужны такие статьи. Куча лирики и мало конкретики. Рассматриваем строковый вывод числа - значит четко как и куда. Нафига лепить в кучу ввод, вывод, приведение типов и прочее? В итоге толком ни-то-ни-сё. Напишите лучше несколько маленьких статей каждая на узкую тему. Еще, если пишете для полных ламеров (а данная статья расчитана именно на таких судя по количеству вылитой воды) , то встретив в первом абзаце фразы типа
то 99.9 из ста дальше читать не станут и в ужасе отложат эту статью подальше. И кстати раз уж зашел разговор о C-строке, то немешало бы упомянуть, что это массив и дальше уже плясать от этого определения Это сообщение отредактировал(а) Fazil6 - 27.12.2007, 19:34 |
|||
|
||||
JackYF |
|
|||
![]() полуавантюрист ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 5814 Регистрация: 28.8.2004 Где: страна тысячи озё р Репутация: 6 Всего: 162 |
zkv, мне понравилось. Основательный подход к делу.
Единственное - навскидку - можно ещё сказать про boost::lexical_cast. А так - молодец. Добавлено @ 19:36 Не согласен. Будет - одна конкретика - так и не будет ничего знать новичок про то, что делает. Использовать функционал надо с умом и пониманием. <cut by archimed7592> да, возможно, стоит упомянуть. Но ставить во главу угла, имхо, не требуется. Это сообщение отредактировал(а) archimed7592 - 27.12.2007, 20:08 |
|||
|
||||
zkv |
|
||||||||||
![]() ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2133 Регистрация: 23.7.2006 Где: Санкт-Петербург Репутация: нет Всего: 92 |
да, мне тоже так показалось, когда увидел все в целом, посмотрим что скажут остальные, и будем разбивать если что. ![]()
да, если нетрудно, то плиз покажите места, где текст труднодоступный, буду переформулировать по возможности. Здесь, кстати, больше интересует мнение неискушенных в вопросе программистов
учтем
учтем Добавлено @ 19:43
заменил на:
![]() Это сообщение отредактировал(а) zkv - 27.12.2007, 19:47 |
||||||||||
|
|||||||||||
Fazil6 |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 7 Всего: 60 |
я бы не стал спорить о том есть здесь ошибка или нет, но то, что упомянуто в скобках , по меньшей мере небрежность и лучше это вообще убрать эту мысль помоему надо как-то подругому озвучить, а то так прямо и подмывает продолжить чем нибудь типа "выпьем, няня, где же кружка?..." понятно, что для новичков, но всетаки давайте не доходить до абсурда, всетаки не для детского сада... Перегрузка конкретного оператора тут, и вообще мне кажется, что статья посвященная преобразованию числа в строку чересчур злоупотребляет выводом на экран. |
|||
|
||||
zkv |
|
||||||||
![]() ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2133 Регистрация: 23.7.2006 Где: Санкт-Петербург Репутация: нет Всего: 92 |
Fazil6, спасибо за замечания!
думаю, как-то надо обозначить, что речь идет именно о том, что люди хотят услышать. Так и правда не однозначно получилось, подумаю как будет лучше (в заголовке особенно не распишешься)
то есть фамильярно слишком или что? ![]()
принято. сделаю примечание ![]()
это так, нужно стараться объяснить в контексте тех вещей, с которыми люди уже знакомы. Внесением исправлений постараюсь заняться завтра, а то вымотался сегодня уже с этой статьей. Пока копим критику ![]() Это сообщение отредактировал(а) zkv - 27.12.2007, 20:34 |
||||||||
|
|||||||||
Fazil6 |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 7 Всего: 60 |
можно дать вначале четкое определение и дальше писать "С-строка" и поменьше отождествлять строку с указателем, типа: Добавлено через 8 минут и 53 секунды нет. Не в этом дело. Не знаю как объяснить. Воспринимается так в контексте, как тост венчающий все предыдущие размышления и прямо думаешь читая : "Аминь. Это я запомню на всю оставшуюся жизнь..." |
|||
|
||||
Ln78 |
|
||||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 274 Регистрация: 25.11.2006 Репутация: нет Всего: 15 |
Как обещал, поучаствую в обсуждении. Хотя в Новогодние праздники времени было бы больше, сейчас, в основном, перечислю то, что хотелось бы увидеть. Но начну с замечания о «замечаниях о стиле». Как-то уж слишком большое внимание уделяется этому вопросу, ИМХО, излишнее. По большому счёту, мы все не Пушкины и даже не Петзолды, чтобы критиковать чужой стиль изложения. По мне, так должно быть и больше лирики, и больше фактического содержания. Рассчитывать на то, что это будут статьи, каких ещё свет не видывал, вряд ли стоит, нужно быть реалистами. А «придраться» по стилю можно почти к любому посту. Например, в первом же комментарии:
если речь идёт о процентах, то нужно писать знак процента, а сто можно и не писать, и так понятно, а если о людях (ламерах), то ужас от страшной судьбы того сотого, одна десятая которого продолжила чтение, в то время как остальная часть занялась чем-то другим. ![]() Собственно, о содержании. Пока из перечисленного в заголовке изложено в основном преобразование целого в символьный вид. Кстати, у ‘0’ всё-таки код 48, а не 49. Хотелось бы побольше и про обратное преобразование, оптимизм в оценке возможностей читателя, конечно, хорошо, но несколько примеров, были бы не лишними. Поскольку в статье упоминались (и это хорошо) функции с возможностями преобразования с учётом системы счисления, то и обратные функции вроде strtoul тоже заслуживают своей доли известности. Пояснить, почему есть функция atof, а обратной для неё нет, перейдя, таким образом к форматированию вообще. Упоминание о бусте есть, а о других возможных классах, специфичных для разных сред разработки нет. Мне кажется, что и такие классы, как CString в MFC/ATL тоже следует назвать. Я уже однажды предлагал рассмотреть задачу вывода
как своего рода «Здравствуй, мир!», чтобы продемонстрировать, как её можно решить наиболее распространёнными способами. В том числе, было бы весьма полезно привести табличку по каждому из рассмотренных вариантов с указанием времени, нужного для преобразования, комментариями о преимуществах и недостатках, например, о том, что для той же CString не нужно заботиться о выделении достаточного объёма памяти, или о непонятной мне робости в вопросах типобезопасности (по мне, так как раз уж в функциях вывода ошибки с неправильной типизацией выявить и устранить наиболее просто). Было бы хорошо сказать, что кроме char могут быть и юникодовские кодировки, сказав и про макрос _T, и про аналоги функций, для работы не только с ANSI-символами, т.е. про функции типа _stprintf. Это сообщение отредактировал(а) Ln78 - 28.12.2007, 08:42 |
||||
|
|||||
zkv |
|
||||
![]() ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2133 Регистрация: 23.7.2006 Где: Санкт-Петербург Репутация: нет Всего: 92 |
память подвела ![]()
ожидал реакции, что слишком объемным материал получается, по-этому не стал пока расписывать. Учту. ок, посмотрю, учту.
гм, спорно, если рассматривать CString, тогда нужно и про AnsiString рассказать, и про QString, что еще у нас есть? А буст таки почти стандарт Хотя просто перечислить со ссылками можно. ![]() поясни пожалуйста, о чем речь? это, думаю, слишком обширная тема, и заслуживает отдельной статьи, здесь достаточно будет оставить ссылку на нее, пока постараюсь найти ссылку на сторонний материал. Про затрачиваемое время сомневаюсь, что хорошая идея. по-моему, это вопрос оптимизации и только, а она, как известно, корень всех зол. Если чел не может отличить приведение типов от конвертации (а зачем иначе он сюда пришел?) то не время еще заниматься вопросами оптимизации, основы языка для начала подучить бы, да стиль выработать. Я даже склоняюсь скорее к тому, чтобы сказать: "Забудьте про быстродействие, используйте то, что вам понятнее/удобнее" Я вообще уже думаю, что неплохо было бы вынести "Способ хранения" и "Способ доступа" в отдельные темы, а во всех темах, касающихся строк ссылаться на них? А то и правда тема получается "все обо всем". P.S. За исправления пока не берусь, думаю правильней будет подождать еще мнений. Пойду пока на баг охотиться ![]() Это сообщение отредактировал(а) zkv - 28.12.2007, 09:24 |
||||
|
|||||
Ln78 |
|
||||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 274 Регистрация: 25.11.2006 Репутация: нет Всего: 15 |
zkv, я думаю, что объёмный материал, это не так уж и страшно. Если речь идёт о достаточно подготовленном человеке, который забыл какую-то функцию, он посмотрит её в справке, MSDN'е. А если пришёл новичок, пусть уж не ленится, а прочитает и побольше, хуже не будет. Да и для более подготовленного тоже хотелось бы что-то иметь (для меня табличку со скоростями
![]()
Так здесь я как раз именно за то, чтобы была обширная коллекция. Я понимаю, что тебе одному это сделать сложно, поскольку одновременно всем ты не пользуешься. Поэтому ещё раз призываю всех дополнить в комментариях своими способами решения задачи, а уж потом ты, приведя всё к единому стилю изложения, возьмёшь эти способы тоже. Такая сравнительная информация была бы полезна и новичкам и многим другим. Возможно, я уже слишком стар и консервативен, но мне непонятны заявления, что printf/sprintf совсем плохи, тяжкое наследие C, в плюсах нужно использовать cout, он-де не имеет ошибок, как например, в случае:
![]() А оптимизация - это совсем не зло. Например, я как-то писал программу, в которой нужно было выполнять преобразование символов в числа и наоборот для нескольких миллионов строк, и там это было весьма кстати. Там даже пришлось писать свою функцию преобразования шестнадцатеричного символьного представления в число, о корректности входных данных там мне заботиться не нужно было, поэтому и на этом тоже удалось сэкономить. ![]() |
||||
|
|||||
zkv |
|
|||
![]() ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2133 Регистрация: 23.7.2006 Где: Санкт-Петербург Репутация: нет Всего: 92 |
||||
|
||||
archimed7592 |
|
||||
![]() Архимед ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2531 Регистрация: 12.6.2004 Где: Moscow Репутация: 6 Всего: 93 |
Думаю, что лучше дать эту ссылку ![]()
Вероятно, что здесь ты хотел подставить другую ссылку. Теперь по содержимому. 1. Ессно нужно описать обратное преобразование. 2. boost и иже с ними идут фтопку. Это новички и заниматься установкой буста(пусть это и обыкновенное копирование одной папки в другую) им противопоказано. 3. Мне кажется, что нужно минимально описать способы "туда" и "обратно" для С и С++. Ручное преобразование можно оформить в отдельную статью. К сожалению, у меня нет такого однозначного мнения на этот счёт, как у Ln78. С одной стороны мне хотелось бы, чтобы новички поскорее становились бы продвинутыми от умных статей zkv. OTOH, я понимаю, что больше половины новичков просто не станут читать так много текста и создадут новую тему(им так проще - с тем же успехом они могли бы прочитать книгу). В общем, оценив все за и против, я пришёл к мнению, что нужно провести декомпозицию. Раз уж начали здесь - то пускай они будут здесь, только нужно визуально разграничить статью от FAQ. Т.е., как мне кажется, почти всю теорию и нестандартные способы нужно вынести в отдельную статью, а в статье для FAQ оставить только то, что реально поможет новичку решить проблему(пусть и без понимания происходящего). Оффтоп про правила был перенесён в тему Пишем правила Это сообщение отредактировал(а) archimed7592 - 15.1.2008, 04:55 -------------------- If you have an apple and I have an apple and we exchange apples then you and I will still each have one apple. But if you have an idea and I have an idea and we exchange these ideas, then each of us will have two ideas. © George Bernard Shaw |
||||
|
|||||
nk19 |
|
||||||
Новичок Профиль Группа: Участник Сообщений: 18 Регистрация: 21.1.2008 Репутация: нет Всего: нет |
Вот у Эккеля нашел. Шаблон для преобразования в std::string и обратно для произвольного типа с операторами << >>
Пример использования
Результат такой:
Если посчитаете нужным, включите в FAQ. Хотя это только обертка над ostringstream. |
||||||
|
|||||||
bsa |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 9185 Регистрация: 6.4.2006 Где: Москва, Россия Репутация: 85 Всего: 196 |
nk19, шаблоны для новичков?!? Ты что!
Если уж на то пошло, посмотри код шаблона boost::lexical_cast - удивишься его простоте и универсальности. |
|||
|
||||
nk19 |
|
|||
Новичок Профиль Группа: Участник Сообщений: 18 Регистрация: 21.1.2008 Репутация: нет Всего: нет |
bsa, не новички тоже могут FAQ читать - для систематизации знаний. Посмотрел lexical_cast, да лучше пример с ним привести, чем мой код.
|
|||
|
||||
![]() ![]() ![]() |
Правила форума "C/C++: Для новичков" | |
|
Запрещается! 1. Публиковать ссылки на вскрытые компоненты 2. Обсуждать взлом компонентов и делиться вскрытыми компонентами
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa. |
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | C/C++: Для новичков | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |