Для проблемы OP все битовое управление становится немного легче освоить, используя некоторую «ручную» развертку l oop.
Плотная упаковка 6 битов каждого байта означает, что
- 8 байтов будут упакованы в 6 байтов, а
- 4 байта будут упакованы в 3 байта
, заканчивающиеся в обоих случаях полным выводом байтов.
Следовательно, я написал al oop, который всегда упаковывает 4 байта одновременно.
Конец ввода может быть не выровнен с 4. Таким образом, существует специальная обработка, необходимая для максимум 3 байтов в конец.
Мой MCVE:
#include <stdio.h>
size_t pack(const unsigned char *message, size_t len, unsigned char *packed_bits)
{
size_t i = 3, j = 0;
// handle bulk
for (; i < len; i += 4, j += 3) {
packed_bits[j + 0] = ((message[i - 3] & 0x3f) >> 0) | ((message[i - 2] & 0x03) << 6);
packed_bits[j + 1] = ((message[i - 2] & 0x3c) >> 2) | ((message[i - 1] & 0x0f) << 4);
packed_bits[j + 2] = ((message[i - 1] & 0x30) >> 4) | ((message[i - 0] & 0x3f) << 2);
}
// handle end (which might be not a full package of 4 bytes)
if (i - 3 < len) {
packed_bits[j++] = message[i - 3] & 0x3f;
}
if (i - 2 < len) {
packed_bits[j - 1] |= (message[i - 2] & 0x03) << 6;
packed_bits[j++] = (message[i - 2] & 0x3c) >> 2;
}
if (i - 1 < len) {
packed_bits[j - 1] |= (message[i - 1] & 0x0f) << 4;
packed_bits[j++] = (message[i - 1] & 0x30) >> 4;
}
// i < len is not possible because it would've been handled in for loop.
return j;
}
void printBits(const unsigned char *buf, size_t len);
int main(void)
{
// sample data
unsigned char message[] = {
#if 0 // gcc extension
0b00001100, 0b00011100, 0b00110100, 0b00111000, 0b00110100, 0b00100100, 0b00010010, 0b00011100,
0b00100100, 0b00010000, 0b00011011, 0b00001110, 0b00001010, 0b00011101, 0b00100101
#else // the same in hex
0x0c, 0x1c, 0x34, 0x38, 0x34, 0x24, 0x12, 0x1c, 0x24, 0x10, 0x1b, 0x0e, 0x0a, 0x1d, 0x25,
#endif // 0
};
const size_t len = sizeof message / sizeof *message;
// output buffer
unsigned char packed_bits[len]; // len is a bit over-pessimistic but definitely sufficient ;-)
// pack the sample
const size_t len_packed = pack(message, len, packed_bits);
// report
printf("message[%zu]:\n", len);
printBits(message, len);
printf("packed to packed_bits[%zu]:\n", len_packed);
printBits(packed_bits, len_packed);
return 0;
}
void printBits(const unsigned char *buf, size_t len)
{
for (size_t i = 0; i < len; ++i) {
unsigned byte = buf[i];
printf(" %c%c%c%c%c%c%c%c",
byte & 0x80 ? '1' : '0',
byte & 0x40 ? '1' : '0',
byte & 0x20 ? '1' : '0',
byte & 0x10 ? '1' : '0',
byte & 0x08 ? '1' : '0',
byte & 0x04 ? '1' : '0',
byte & 0x02 ? '1' : '0',
byte & 0x01 ? '1' : '0');
}
putchar('\n');
}
Вывод:
message[15]:
00001100 00011100 00110100 00111000 00110100 00100100 00010010 00011100 00100100 00010000 00011011 00001110 00001010 00011101 00100101
packed to packed_bits[12]:
00001100 01000111 11100011 00110100 00101001 01110001 00100100 10110100 00111001 01001010 01010111 00000010
Live Demo на coliru
Я сравнил свой вывод с ожидаемым выходом OP, и они совпадают.
Вход OP и мой:
00001100 00011100 00110100 00111000 00110100 00100100 00010010 00011100 00100100 00010000 00011011 00001110 00001010 00011101 00100101
00001100 00011100 00110100 00111000 00110100 00100100 00010010 00011100 00100100 00010000 00011011 00001110 00001010 00011101 00100101
Точно равны.
Ожидаемый выход OP и шахты:
00001100 01000111 11100011 00110100 00101001 01110001 00100100 10110100 00111001 01001010 01010111 00000010
00001100 01000111 11100011 00110100 00101001 01110001 00100100 10110100 00111001 01001010 01010111 00000010
Точно равен.