Как стать автором
Обновить

Побайтовое заполнение массива

Привет, друзья. Хочу поделится с вами опытом программирования на языке С++. В этой статье я бы хотел рассказать про побайтовое заполнение массива, а именно о том, что это такое и зачем это вообще нужно.
Статья адресована начинающим программистам. Если я оказался где-то неправ, то с радостью приму замечания.

Массивы и их содержимое


Когда я начинал работать с массивами в C++ (а я научился программировать именно при помощи этого языка), я даже не задумывался о том, как происходит их заполнение на более низком уровне. Возьмем вот такой простой пример. Имеются две целочисленные беззнаковые переменные:
unsigned char byte = 255; // [11111111]
unsigned short int twoBytes[2] = {0, 0}; // [00000000|00000000, 00000000|00000000]

Допустим я хочу заполнить объявленный массив twoBytes двумя значениями byte. Что в этом случае сделаете вы? Правильно, вы сделаете так:
twoBytes[0] = byte; // [00000000|11111111, 00000000|00000000]
twoBytes[1] = byte; // [00000000|11111111, 00000000|11111111]
printf("First element: %i,\tSecond element: %i\n", twoBytes[0], twoBytes[1]);	// First element: 255, Second element: 255

Вроде бы все хорошо, вывод такой, каким мы его и ожидали. Но давайте посмотрим на заполнение массива на более низком уровне.

«Хождение» по массиву n-байтовыми шагами


До начала «хождения» давайте сначала немного поговорим о числовых типах в языке C++, а именно о тех, которые, я использовал в примере. Не для кого ни секрет, что тип char занимает в памяти не меньше 1 байта, а тип short int (или просто short) не меньше 2 байт. В данном случае я рассматриваю их беззнаковые (unsigned) реализации. Более наглядно о количестве занимаемых бит я написал в комментариях к коду. Вертикальная черта в текущем контексте разделяет байты для наглядности.
Теперь вернемся к коду заполнения массива и начнем «хождение». После первого присваивании видно (см. комментарии к коду), что 1 элемент массива twoBytes заполняет свои 2 байта 1-байтовым значением переменной byte. После 2 присваивания 2 элемент массива twoBytes по аналогии заполняет свои 2 байта 1-байтовым значением переменной byte.
Так что же получается, 2-байтовый элемент массива заполняется не полностью? Да, это действительно так. Но почему так происходит? Дело в том, что при перемещении по байтам массива, его заполненность будет зависеть от размера «шага» (а точнее, размера типа данных), с которым мы «ходим» по его байтам (pointer arithmetic).
В данном примере мы «ходим» по байтам 2-байтовыми «шагами», так как размер типа short int 2 байта и поэтому мы пропускаем 1 байт элемента массива short int. Самым очевидным решением этой проблемы будет уменьшение «шага» до 1 байта. На языке С++ это можно сделать так:
( (unsigned char*)twoBytes )[0] = byte;	// [00000000|11111111, 00000000|00000000] - первый шаг
( (unsigned char*)twoBytes )[1] = byte;	// [11111111|11111111, 00000000|00000000] - второй шаг
printf("First element: %i,\tSecond element: %i\n", twoBytes[0], twoBytes[1]);	// First element: 65535, Second element: 0

То есть в данном случае мы приводим указатель (имя массива — это указатель на начало куска памяти, который выделен под массив) на 2-байтовый тип unsigned short int к указателю на 1-байтовый тип unsigned char, тем самым уменьшая «шаг» до 1 байта. В итоге элемент массива заполняется полностью, так как каждый новый «шаг» — это побайтовый проход.

Для закрепления полученного материала можно поиграться с другими беззнаковыми типами.
Для чего это вообще нужно? Пусть этот вопрос останется пищей для размышления.
Спасибо за внимание.
Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.