Почти полтора месяца писала данную статью, но надеюсь оно того стоило. Данная статья может выглядеть холиварной, поэтому не спешите писать комментарии пока не прочитаете полностью. Статья главным образом о методологии.
Дело в том, что я твёрдо уверена, что в учебных заведениях по информационной специальности, школьникам и студентам забивают голову историей древнего мира вместо актуальных знаний. Все методички преподают дамы бальзаковского возраста, а пишут эти методички профессора возраста Карла Маркса. В результате от соискателей на работу, и от стажёров, я слышала такие забавные заблуждения, относительно фундаментальных основ, как:
- в байте 1024 бита
- в байте 8 бит потому что 8 — степень двойки
- бит принимает всякие разные значения от 0 до 1
В числе прочих забавных случаев: для выбора десяти случайных чисел из бд, соискатели десять раз делают запрос; для открытия файла на чтение используют в PHP флаг 'a+'; не умеют работать со строками, кодировками и указателями. Написать функцию, которая возвращает строку задом наперёд, не используя переменную-буфер — вообще непосильная задача.
В этой статье, я хочу коснуться проблемы заблуждений с битами и байтами, и написать свою методику обучения этим фундаментальным знаниям.
Итак… сперва я хочу написать определения из википедии методичек, которые являются догмой в умах профессоров из мин.образования.
- Бит — это двоичный логарифм вероятности равновероятных событий или сумма произведений вероятности на двоичный логарифм вероятности при равновероятных событиях; (или другими словами) бит — это единица информации, равная результату эксперимента, имеющему два исхода
- Бит — минимальная единица информации.
- Байт — минимальная адресуемая единица информации.
Из-за этих определений, в умах будущих программистов ЭВМ, больше каши, чем из-за каких-либо других определений! Они совершенно истинны, но совершенно бесполезны для обучения. Я превращаюсь в Халка, когда слышу их.
Про биты
Итак, дети, садитесь, урок первый, представьте себе выключатель. Нет, не двоичный логарифм вероятности… А обычный такой выключатель, тумблер, рычажок, что угодно, включающее например лампочку, когда находится в одном положении и выключающее в другом. На некоторых рычажках даже подписывают буковки I/O, как указатели положений ручки. Нет, выключатель не несёт в себе информацию. Он выключает свет.
У выключателя есть два положения — вкл/выкл. Если мы поставим рядом два выключателя, то количество комбинаций позиций, которое могут занимать их ручки — четыре. (Когда оба выключены, когда оба включены, и две комбинации когда включен только один из них). Если мы возьмём систему из трёх выключателей — они смогут занимать восемь комбинаций. И так далее, N выключателей имеют 2^N
комбинаций. Выключатель который имеет только два положения (вкл/выкл) мы можем назвать битом. Если мы представим, что положениям вкл/выкл соответствуют числа 1 и 0, то можно легко записать какое-нибудь целое число в двоичной системе счисления, используя только последовательный набор выключателей, так чтобы каждый выключатель отвечал за свой двоичный разряд.
Безусловно выключатели мы можем применить к магнитной дорожке, или оптическому диску, так, чтобы при помощи специального устройства можно было «включать» или «выключать» их маленькие участки. Теперь мы наконец подошли к тому, что все компьютерные запоминающие устройства состоят из «ноликов и единичек».
Однако, в этих ноликах и единичках нам надо хранить информацию. Какую же информацию нам можно хранить? Давайте рассмотрим один бит. Мы можем условно договориться, что он может хранить информацию, и два его состояния вкл/выкл содержат значения «баклажан» и «не баклажан» соответственно. Это отлично подходит, когда нам надо произвести учёт баклажанов! Однако в реальном мире компьютеры, которые умеют только считать баклажаны — не пользуются спросом. Выходит выключатель (бит) не может нести в себе информацию. Чтобы записывать ноликами и единичками какую-то информацию, было решено группировать их по несколько штук, и такую группу называть байтом.
Байт
На заре компьютеров байты составляли 4, потом 5, потом 6 бит… Группа из 6 бит может принимать целых 64 значений. Вполне неплохо, так как можно создать некую таблицу соответствий этих значений определённым символам — кодировку. Такая кодировка уже может содержать цифры и заглавные буквы латинского алфавита, а также некоторые арифметические знаки. «Шестибитные-кодировки» — применялись на компьютерах в 1950-х — 1960-х годах.
Для человека который только начинает изучать информатику, будет понятно и легко запомнить что байт — является минимальной единицей информации. В байт можно записать какое-нибудь число, либо например какой-нибудь символ из таблицы символов (англ. charset, буквально «набор символов») — кодировки (codepage, encoding).
С развитием компьютеров, появилась потребность в большем количестве значений для байта. В 1963-м году появилась первая редакция семибитной кодировки ASCII. Поэтому байты стали занимать 7 бит. 7 бит, требующиеся для одного символа данной кодировки позволяют использовать 128 значений. В этой кодировке уже были включены строчные латинские символы, и больший набор управляющих и арифметических символов.
Всемирное распространение компьютеров подтолкнуло дальнейшее расширение границ занимаемых байтом. Для различных языков требовалось чтобы таблица символов также могла хранить алфавит того языка, где используется данная ЭВМ. На текущий момент восемь — это последнее и видимо окончательное количество бит составляющих байт. Соответственно байт может принимать 256 значений. По сравнению с таблицей ASCII в. новых таблицах символов — организовалось 128 вакантных мест. Теперь я думаю можно рассказать как значения хранятся в различных кириллических кодировках.
Кодировки
Итак, чтобы хранить символы не входящие в ASCII, необходимо было придумать новые кодировки. Поскольку до этого таблица ASCII была наиболее подходящей (были и другие), то она и пошла в основу новых кодировок. Поэтому следующие кодировки отличаются только значениями начиная с 80 (hex). Для наглядности оставлю только кириллические символы.
Так выглядела наиболее популярная кодировка под DOS. Примечательно что файлы в этой кодировке до сих пор встречаются. Как правило среди устаревшей архивной информации, в программах WinRar, Блокнот и WordPad, до сих пор есть опции «открыть как текст DOS», впрочем последними двумя мало кто пользуется =).
Кодировка koi8 была примечательна тем, что русские буквы там располагались на позициях английских звуков из нижней половины (т. е. ASCII). Это когда-то давно позволяло смягчить переход со старых серверов понимающие только ascii на новые, что было актуально среди почтовых серверов. Смысл был в том что если отправленное вами письмо приходило на старый сервер, то пользователю оно показывалось как транслит, что позволяло хоть как-то понять текст письма.
Самая популярная у нас в России однобайтная кодировка, на сегодняшний день, это именно «windows-1251». Разумеется популярность её целиком обусловлена популярностью Windows среди других операционных систем. Возможностей кодировки вполне хватает для использования её в широком круге задач. Например движок моего блога, по-умолчанию, использует для работы именно данную кодировку.
Я не могу не упомянуть о кодировке ISO, Удивительно, но несмотря на то что её никто никогда не использовал, эта кодировка является единственной кодировкой имеющей статус стандарта.
На примере данных кодировок видно, как один байт может хранить какое угодно символьное значение русского и английского языков, а также цифр и знаков пунктуации.
Но что делать когда этого не достаточно?
Многобайтные кодировки
Если вам хочется создать кодировку которая бы имела коды одновременно для русского и греческого алфавита? Одним байтом тут не отделаться. Появилась задача разработать кодировку один знак которой может занимать больше чем один байт, так как два байта могут принимать уже 2^16 = 65536 значений, а четыре байта аж 4294967296. Поэтому сначала придумали стандарт кодирования символов — Юникод, который включал бы в себя максимально полный перечень символов которые может принимать один знак.
Первая версия Юникода (Unicode 1991 г.) представляла собой 16-битную кодировку с фиксированной шириной символа; общее число разных символов было 216 (65 536).
Вторая версия Юникода (UCS-2), стала называться UTF-16, она позволяла гораздо расширить количество возможных значений, также используя для символов 16-битные последовательности (т. е. по 2 или по 4 байта на символ).
Символы с кодами 0×0000.0xD7FF и 0xE000.0xFFFF представляются одним 16-битным словом, а символы с кодами 0×10000–0×10FFFF — в виде последовательности двух 16-битных слов. Количество символов, представляемых двумя 16-битными словами равно (220). Для представления символов с кодами 0×10000–0×10FFFF используется матрица перекодировки. Первое слово из двух переданных лежит в диапазоне 0xD800-0xDBFF, а второе — 0xDC00-0xDFFF. Именно этот диапазон значений не может встречаться среди символов, передаваемых с помощью одного 16-битного слова, так что расшифровка кодировки всегда однозначна. Ясно, что имеется как раз 210 * 210 = 220 таких комбинаций.
Кодировка UTF-32 (UCS-4) использует по 32 бита, или 4 байта на хранение одного символа. Строго говоря, стандарт Unicode не описывает символы со значениями выше 2^21, так что хватило бы и трёх байт, на символ, вероятно компьютеры работают несколько быстрее с мелкими блоками памяти кратными двум, или для того чтобы в сектор диска попадало кратное количество символов. Так или иначе это единственная из многобайтных кодировок с постоянной длиной. Помимо недостатка — использования четырёх байт на символ, у неё есть и очевидное преимущество — возможность прямой адресации к N-ному символу. В других кодировках требуется последовательное вычисление позиции каждого символа. Поэтому текстовые редакторы, внутри себя хранят всю информацию в виде UCS-4.
В 1992 году Кеном Томпсоном и Робом Пайком был изобретён формат UTF-8. Он отличается тем, что он ASCII совместим, и значения из таблицы Юникода могут занимать от 1 до 4х символов.
Символы UTF-8 получаются из Unicode следующим образом:
Unicode | UTF-8 | Представленные символы |
---|---|---|
0×00000000 — 0×0000007F |
0xxxxxxx |
ASCII, в том числе английский алфавит, простейшие знаки препинания и арабские цифры |
0×00000080 — 0×000007FF |
110xxxxx 10xxxxxx |
кириллица, расширенная латиница, арабский, армянский, греческий, еврейский и коптский алфавит; сирийское письмо, тана, нко; МФА; некоторые знаки препинания |
0×00000800 — 0×0000FFFF |
1110xxxx 10xxxxxx 10xxxxxx |
все другие современные формы письменности, в том числе грузинский алфавит, индийское, китайское, корейское и японское письмо; сложные знаки препинания; математические и другие специальные символы |
0×00010000 — 0×001FFFFF |
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
музыкальные символы, редкие китайские иероглифы, вымершие формы письменности |
Символы, в кодировке UTF-8, могут занимать до шести байт, но Unicode не определяет символов выше 0×10ffff
, поэтому символы Unicode могут иметь максимальный размер в 4 байта в UTF-8.
Заключение
Вот собственно и всё что я хотела рассказать. Я считаю что очень интересно разбираться в том как работает компьютер, знать как хранятся в нём символы которые я набираю на клавиатуре, представлять насколько однобайтная кодировка например win-1251 (или utf-32 с фикс. длиной) работает быстрее со строковыми функциями и почему и т. п. Надеюсь статья вам понравилась.
Большое спасибо Википедии за возможность скопировать цитаты и таблицы, а то бы писала статью ещё месяц.
Все кто хочет узнать больше, также могут почитать про то в каком порядке записываются байты в кодировках UTF-16 и UTF-32 — в википедии тут и тут. А также что такое порядок байтов тут: Порядок_байтов. Также интересна будет статья Юникод в операционных системах Microsoft.
Комментарии:
@ (Дмитрий Липин)
12.10.2011 17:46:55
Елена Лунная
13.10.2011 02:21:16
SelenIT
27.01.2012 04:48:19
Елена Лунная
27.01.2012 05:42:39
SelenIT
27.01.2012 12:44:31
Елена Лунная
27.01.2012 21:25:48
SelenIT
27.01.2012 22:07:43
Елена Лунная
27.01.2012 22:30:38
SelenIT
27.01.2012 22:49:00
notisster
17.02.2012 16:29:21
Елена Лунная
18.02.2012 01:53:37
гость
19.05.2012 20:02:45
26.02.2013 16:47:07
Юлия
23.05.2013 15:42:33
Елена Лунная
23.05.2013 21:08:51
10.06.2013 20:28:23
Елена Лунная
11.06.2013 00:06:44
аноним
23.08.2013 22:40:59
Елена Лунная
23.08.2013 22:50:26
дизойнёр
17.01.2014 15:59:56
Елена Лунная
17.01.2014 16:37:36
да так заглянул
10.04.2014 21:13:39