Доступны опции
Для управления большим структурированным набором битов у вас есть следующие опции:
Битовые поля C ++ : вы определяете структуру с элементами битового поля. У вас может быть столько членов, сколько хотите, при условии, что у каждого из них не больше битов, чем unsigned long long
. Его очень легко использовать; Компилятор управляет доступом к битам или группам бит за вас. Основное неудобство заключается в том, что битовая раскладка зависит от реализации. Таким образом, это не вариант для написания переносимого кода, который обменивается данными в двоичном формате.
Контейнер целочисленного типа без знака : вы определяете массив, достаточно большой для хранения все биты и биты доступа или группы битов с использованием комбинации логических операций. Это требует облегчения работы с двоичными операциями и непрактично, если группы битов разбиты на последовательные элементы. Для удобного обмена данными в двоичном формате с внешним миром необходимо либо позаботиться о различиях между архитектурами big и little endian, либо использовать массивы uint8_t
.
std::vector<bool>
: дает вам полную гибкость в управлении битами. Основное ограничение заключается в том, что вам нужно адресовать каждый бит отдельно. Более того, нет элемента data()
, который мог бы предоставить прямой доступ к двоичным данным.
std::bitset
: очень похоже на vector<bool>
для доступа к битам. Он имеет фиксированный размер во время компиляции, но предлагает полезные функции, такие как чтение и запись двоичного кода в ascci из строк или потоков] 5 , преобразование двоичных значений целочисленных типов и логические операции над полным набором бит.
Комбинация этих методов
Сделайте свой выбор
Чтобы общаться с внешним миром портативным способом, Самый простой подход - использовать битовые наборы. Наборы битов предлагают простое преобразование ввода / вывода / строки в формат с использованием ascci '0' или '1' (или любые их заменители)
bitset<msg_header_size> bh,bh2;
bitset<msg_body_size> bb,bb2;
cin>>bh>>bb; // reads a string od ascii 0 and 1
cout<<bh<<"-"<<bb<<endl<<endl; // writes a string of ascii 0 and 1
Вы также можете преобразовать из / в двоичные данные (но с одним элементом , достаточно большой для размера битового набора):
bitset<8> b(static_cast<uint8_t>(c));
cout<<b<<endl;
cout<<b.to_ulong()<<endl;
Для чтения / записи больших наборов вам нужно будет читать маленькие битовые наборы и использовать логические операторы для их агрегирования в больший битовый набор. Это кажется трудоемким, на самом деле это очень похоже на то, что вы делали бы в контейнерах интегралов, но без необходимости заботиться о границах байтов.
В вашем случае с заголовком фиксированного размера и максимальным размером , bitset
кажется хорошим выбором (однако будьте осторожны, поскольку переменная часть выровнена по правому краю) для обмена двоичными данными с внешним миром.
Для работы с содержимым данных легко получить доступ к определенному c бит, но вы должны использовать некоторые логические операции (сдвиг и) для доступа к группам битов. Более того, если вам нужен читаемый и поддерживаемый код, лучше абстрагироваться от битовой схемы.
Вывод:
Поэтому я настоятельно рекомендую использовать внутренне битовое поле структура для работы с данными и сохранение сопоставимого объема памяти, чем исходные данные и в то же время, используйте битовые наборы только для преобразования из / в эту структуру с целью внешних данных обмены.