Пожалуй, не найти в информационных технологиях области наиболее похожей на помойку. В этот раз поговорим о том, через какие страдания пришлось пройти в программировании такой абстракции, как текстовые строки. И если до сих пор употребляется выражение "слетела кодировка", то точка в конце этой строки еще не поставлена.
ASCIIZ
В наше время мы привыкли обсуждать сложнейшие концепции фреймворков и высокоуровневых языков программирования. Это злосчастное определение "высокоуровневый" приравнивается к "высокопрофессиональный" или чему-то подобному высокопарному. Однако, эти высокие замки строятся если не из песка, то на песке. Более того, если за дело берется специалист, изучавший программирование и использовавший все это время готовый фреймворк, то песок, на котором будет строиться замок из песка будет еще и зыбучим.
Бурное развитие информационных технологий началось где-то 50 лет назад, когда в университетах появились достаточно доступные компьютеры. До появления первых микрочипов процессоров еще несколько лет, в связи с этим, основной технологией строительства компьютеров и процессоров для них являлась пайка простейших микросхем вроде 14-контактных 2ИЛИ-НЕ.
На базе такого сурового компьютера (PDP-11) широко использовалась одна из первых концепций текстовых строк.
Это, так называемые, строки с завершающим нулем. Они же нуль-терминированные строки (ASCIIZ).
Главной особенностью такого хранилища букв является их кодирование по таблице ASCII и самое главное - окончание строки это нулевой байт.
Недостатки ASCIIZ строк
Что касается таблицы кодирования букв... Вы заметили тут символы кириллицы? Вот именно) Их тут нет. С самого порога нам предложили учить английский язык или убираться из IT. Ни немцы, ни французы ни советские граждане абсолютно не расстроились, а приняли свои кодировки символов алфавитов. И то, что эта идея пришла в голову всем одновременно стало настоящей бедой.
Свойственные другим языкам буквы расположились после адреса 7F в вышеуказанной таблице. Понятное дело, попытка открыть болгарский текст используя русский текстовый редактор оканчивалась удивленными глазами читателя, смотрящими на бессмыслицу. Для описания эффекта был введен жаргонный термин "кракозябры".
Кроме того, что мы сами себе придумали кодировку, для нас постаралась и Microsoft. Даже русскоязычный текст можно записать в разной кодировке. При чтении текста программой можно было увидеть "Я СБЮФЕМХЕЛ", что означало всего лишь "с уважением".
Наиболее опасными последствиями использования нуль-терминированных строк были и есть: падение производительности при операциях над текстом и возможность хакерской атаки через переполнение хранилища длинной строкой, не влезающий хвост который хлестал по адресу возврата из функции. Возврат по адресу, нужному хакеру давал ему возможность исполнить свой код. Для лучшего понимания на этом канале есть статья про вызовы функций и стек.
Почему-же столь минималистичная конструкция ставит на колени производительность процессора? Дело в том, что в ней нет места для хранения такой сверхважной характеристики, как ее длина. Попробуйте создать простейший текстовый редактор, где нужно копировать и вставлять фрагменты текста друг в друга и все станет понятно. Без знания длины строк этого не сделать. А как вычислить длину строки? Оказывается, нужно пошагово дойти от ее первого символа до нуля (окончание строки). Пошагово, друзья). А как же функция strlen(), возвращающая длину строки? С прискорбием сообщаю, что у нее под капотом пошаговая проверка на нулевое окончание строки. В-общем,
нуль терминированные строки это сплошной стыд, который за годы программистского труда проник в кучу софта по всему миру.
Pascal строки
Разработчики компилятора одного популярного в тот момент языка программирования решили проблему без всяких изысков. Почему бы не поместить нулевым байтом размер строки?
Один байт это очень мало, он ограничивает максимальный размер строки до 255 символов. Впрочем, это новшество также растворилось в миллионах строк кода. Это на самом деле решило проблему производительности, но только за исключением тех гастарбайтерских творений где самое лучшее было вроде этого:
char * str = "*Очень длинная строка";
str[0] = strlen(str)-1; //опять пошаговый strlen :)
Если кто-то не заметил, это Pascal строка, оканчивающаяся нулем. Стыд? Безусловно. Производительность поднялась, но защиты от хакеров никакой.
Стоит отметить, что такие строки стали основой программного продукта всемирной известности Microsoft Excel. Если не изменяет память, длина строки там ограничивалась 255 символами.
Решение азиатской проблемы
Когда проблемы кодировок букв, скорости обработки и безопасности превысили все терпимые пределы, начали появляться более универсальные решения. Попытка учесть все многообразие языков нашей планеты привела к созданию набора символов Unicode.
Самое большое заблуждение программистов это считать, что Unicode является 16-битными кодами c возможностью кодирования 65536 различных символов. Если посмотреть на коды слова "Hello", то это, действительно, будут 16-ричные числа: 0х0048, 0х0065, 0х006С, 0х006С, 0х006F. А как на счет того, что разные архитектуры процессоров предусматривают различный порядок хранения старших и младших байт? Одно неверное движение и "Hello" уже совсем не "Hello". Вынужденной мерой стало введение в состав строки двух байт, являющихся маркером порядка байтов. Что-то начинается уже немного стыдно...
Перерасход байт на хранение строк с английскими буквами (лишние нули!) привел к противоречивому решению. Для всех символов, что умещаются в 1 байт и будет выделяться 1 байт, но зато остальным национальным алфавитам прийдется не сладко. А кого из англосаксов когда волновали чужие проблемы? Держите все те, кто не может произнести "the" без акцента:
- Английские буквы (коды 0x00-0x7А) 1 байт на каждую : 0bbbbbbb
- Прочие: (коды 0x80-0x7FF) 2 байта на букву: 110bbbbb 10bbbbbb
- (коды 0х800-0хFFFF) 3 байта на букву: 1110bbbb 10bbbbbb 10bbbbbb
- и так далее вплоть до 5 байт на букву..
1 или 0 означают фиксированные биты префикса, b-любые биты. По префиксу можно понять в какой части таблицы нужно искать изображаемый символ.
По мне, так ужас какой-то. Одно ясно -
строка не имеет никакого смысла если не знать кодировку.
В корне всех бед, в частности, когда пользователь вместо "Привет" получает "??????" лежит уверенность программиста в том, что текст это ASCII код и кодировка в нем такая, как он думает.
Эпилог
Это все далеко не полный перечень попыток закодировать буквы национальных алфавитов. Программисты на сегодняшний день худо-бедно научились не показывать нам "????? ???? ?" Помогают им в этом подсказки в разметке HTML страниц вроде: Content-Type: text/plain; charset="UTF-8", также масса различных классов-абстракций со своими системами хранения строк (std::string, CString, String, wstring, QString и прочие). Эти классы в языках программирования обладают свойствами, среди которых теперь обязательным является длина строки. Как мы теперь точно знаем, это практически синоним безопасности и производительности. Методы этих классов способны конвертировать один формат представления в другой. Конечно, далеко не в каждый известный формат, но этого и не требуется. Работает хоть как-то и уже хорошо.
Поддержите статью лайком если понравилось и подпишитесь чтобы ничего не пропускать.
Также не обойдите вниманием канал на YouTube. Подписки и лайки будут приятным ответом от аудитории.