Как можно выделить под переменную или поле структуры определенное количество бит?
Допустим, есть у меня символ 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(¤tCharCode, sizeof(int), 1, outFile);
// В функции распаковки
fread(&codeInFile, sizeof(int), 1, inFile);
У меня есть структура Word
typedef struct Word {
unsigned int code;
char * value;
} Word;
Подскажите, как можно выделить под ее поле code определенное количество бит или убрать лишние нули из файла с кодами. А то вместо сжатия получается какое-то раздутие.
Ответы (3 шт):
Нет, нельзя. Любая память ОЗУ представляет собой линейный массив байт, обращаться к которому можно исключительно по адресам. Биты же не имеют адреса.И исходя из вашего вопроса, предлагаю изучить мастчасть глубже, в особенности то, каким образом представляются в памяти чары и строки.
Нет, минимально адресуемая единица памяти - байт.
Для 9-16 бит понадобится уже двухбайтовая переменная и так далее.
При необходимости экономии данные промежуточного размера можно упаковывать - например, 8 10-битных единиц можно уложить в 10 байтов и затем вытаскивать нужную с использованием битовых операций (в C/С++ можно также битовые поля применять)
Возможно (задачу мы не знаем), Вам требуется что-то вроде кодирования Хаффмана, когда для символов исходного текста с разной частотностью создаются специальные (бес)префиксные коды разной длины в битах (для частых - короче), а свойства этих самых кодов позволяют извлекать их затем из упакованной битовой последовательности.
Как можно выделить под переменную или поле структуры определенное количество бит? - как вариант - для этой цели лучше всего использвать bitstream - битовый поток.
Про LZW
Если хотите хорошо разобраться - нужно ознакомится с
- упаковка байт в биты
- распаковка бит в байты
- Булевая алгебра: как проверить бит (операция 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 скинуть на диск, или куда нужно.