Как можно выделить под переменную или поле структуры определенное количество бит?

Допустим, есть у меня символ a с кодом 98. Он помещается в 1 байт (8 бит). Я могу написать

unsigned char ch = 98;

И в 8 бит поместятся коды от 0 до 255. Но если у меня будет, скажем, строка ab и я назначу ей код 256, то он уже в ch не поместится. Можно ли как-то выделять память под переменную в битах? Сначала 8 бит, если встретили код 256-511 — выделим 9 бит, встретили 511 < число > 1023 — ему 10 бит т.д.

malloc, calloc и realloc оперируют байтами.

Я пытаюсь реализовать алгоритм сжатия данных без потерь LZW. Из строки abacabadabacabae, которая находится у меня в файле, я получил файл с бинарным кодом. Вот Его содержимое

    6100 0000 6200 0000 6100 0000 6300 0000
    0001 0000 6100 0000 6400 0000 0401 0000
    0301 0000 0101 0000 6500 0000

Я смог расшифровать его по заданному алгоритму и получить исходную строку. Но есть одна проблема — "сжатый" файл занимает не 10 байт как должен, а 40, потому, что я записывал в файл и читал из него int'ы.

 // в функции сжатия   
 fwrite(&currentCharCode, sizeof(int), 1, outFile);
 // В функции распаковки
 fread(&codeInFile, sizeof(int), 1, inFile);

У меня есть структура Word

 typedef struct Word {

  unsigned int code; 
  char * value; 
  } Word;

Подскажите, как можно выделить под ее поле code определенное количество бит или убрать лишние нули из файла с кодами. А то вместо сжатия получается какое-то раздутие.


Ответы (3 шт):

Автор решения: Александр Привалов

Нет, нельзя. Любая память ОЗУ представляет собой линейный массив байт, обращаться к которому можно исключительно по адресам. Биты же не имеют адреса.И исходя из вашего вопроса, предлагаю изучить мастчасть глубже, в особенности то, каким образом представляются в памяти чары и строки.

→ Ссылка
Автор решения: MBo

Нет, минимально адресуемая единица памяти - байт.

Для 9-16 бит понадобится уже двухбайтовая переменная и так далее.

При необходимости экономии данные промежуточного размера можно упаковывать - например, 8 10-битных единиц можно уложить в 10 байтов и затем вытаскивать нужную с использованием битовых операций (в C/С++ можно также битовые поля применять)

Возможно (задачу мы не знаем), Вам требуется что-то вроде кодирования Хаффмана, когда для символов исходного текста с разной частотностью создаются специальные (бес)префиксные коды разной длины в битах (для частых - короче), а свойства этих самых кодов позволяют извлекать их затем из упакованной битовой последовательности.

→ Ссылка
Автор решения: nick_n_a

Как можно выделить под переменную или поле структуры определенное количество бит? - как вариант - для этой цели лучше всего использвать bitstream - битовый поток.

  1. http://stackoverflow.com/questions/264552/c-c-code-to-treat-a-character-array-as-a-bitstream

Про LZW

  1. https://www.geeksforgeeks.org/lzw-lempel-ziv-welch-compression-technique/

  2. http://www.cplusplus.com/articles/iL18T05o/

Если хотите хорошо разобраться - нужно ознакомится с

  • упаковка байт в биты
  • распаковка бит в байты
  • Булевая алгебра: как проверить бит (операция AND), как установить бит, как сбросить бит
  • битовый поток.

Символы в упакованом потоке соовсем не соответствуют ничему. Их более менее удобно читать в hex представлении. В bin тоже удобно, но сильно раздуто. Хотя депаковщики удобно показывать побитно.

Для "запаковки" бит в массив можно сделать где-то так (грубо)

 void writeBits( char * data, int value , int bitoffs ) {
      //       делим_на_8 минус 3 бита       а тут з бита для сдвига             
   *((int*)&data[bitoffs>>3])  |=  value << (bitoffs & 7);

   }

Будет работать при условии что data изначально чистый, value - до 23-бит. Так же нет контроля, можно добавить маску для устойчивости и т д. Если эти условия не выполняются - код нужно усложнять

У меня есть структура Word, Подскажите, как можно выделить под ее поле code определенное количество бит или убрать лишние нули из файла с кодами. А то вместо сжатия получается какое-то раздутие.

Из code - убирать лишние биты не нужно*, она просто должна больше либо равно бит чем вам нужно. Лишние биты уйдут в процессе паковки в битовый поток. (* - нету явной технической возможности, даже если вы сделаете битовое поле, то при операциях записи - всёравно будет выравнивание до байта)

Например можно так

char dest[256] = {0,}; // К-во нужно вычислить, 
// его делают или достаточно большим под "пакет"
// либо зараннее вычисляют и делают malloc/alloc
// либо динамически расширяют (редко)
int bitoffs = 0;
int bitcount= 5; // указать сколько бит пишется
writeBits(dest, word1.code, bitoffs );
writeBits(dest, word2.code, bitoffs + bitcount );
writeBits(dest, word3.code, bitoffs + bitcount*2 );
// и так далее, потом массив dest скинуть на диск, или куда нужно.
→ Ссылка