Search
Write a publication
Pull to refresh

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

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

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


Когда я начинал работать с массивами в 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 байта. В итоге элемент массива заполняется полностью, так как каждый новый «шаг» — это побайтовый проход.

Для закрепления полученного материала можно поиграться с другими беззнаковыми типами.
Для чего это вообще нужно? Пусть этот вопрос останется пищей для размышления.
Спасибо за внимание.
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.