Переиндексация битов внутри символа - PullRequest
0 голосов
/ 25 июня 2019

У меня есть упражнение, в котором я должен кодировать и декодировать строки на уровне битов, которые задаются в командной строке.

Предостережение для этого заключается в том, что я должен использовать преобразование перестановки, чтобы переупорядочить биты.

Вот пример:

Пользователь вводит символ для кодирования

 H

Двоичный для H составляет

 01001000 

Однако это обычное отображение 8 битов через 0-7.

Моя программа должна будет переставлять биты в любой используемый мной картографический паттерн.

Например, если я использую Mapping 64752031

Биты для Чар 'H'

01001000 

Поворот к

01000001

При кодировании символа 0-й бит превращается в 6-й бит, 2-й бит превращается в 4-й бит, 3-й бит превращается в 7-й бит и так далее. На чем основано это отображение.

Есть ли способ, которым я могу манипулировать и изменять порядок битов на основе данной карты перестановок?

Спасибо.

Ответы [ 4 ]

3 голосов
/ 25 июня 2019

Если вам нужно обработать большие строки, вероятно, лучше использовать справочную таблицу, которая будет предварительно вычислять перевод.

#include <stdio.h>

unsigned char perm[256];  // permutation table
unsigned mapping[8]={6,4,7,5,2,0,3,1};
// assumes    7 6 5 4 3 2 1 0
//       =>   6 4 7 5 2 0 3 1

void mkperm(unsigned char perm[256]) {
  for (int i=0; i<256; i++)
    perm[i]=0;

  for (int i=0;i<256;i++) {
    for (int j=7; j>=0; j--) {
      int pos=mapping[7-j]; // at mapping[0] is the new position of bit 7
      if (i & (1<<j))       // only considers set bits, the table is previously cleared
        perm[i] |= (1<<pos) ;
    }
  }
}

int main() {
  mkperm(perm);
  printf("%.2x => %.2x\n",'H',perm['H']);
}

mkperm() вычисляет таблицу перестановок путем сканирования последовательных битов каждого символа. Если бит установлен в char i, мы устанавливаем в позиции i в таблице перевода бит в единицу с логическим весом, заданным отображением. Установка этого выполняется путем выравнивания содержимого ячейки i с правильным смещением 1.

1 голос
/ 25 июня 2019

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

#include <stdio.h>
#include <limits.h>
#include <stdint.h>

char encode( char c, uint32_t mask )
{
    unsigned char result = '\0';

    for ( size_t i = 0; i < 2 * sizeof( mask ) ; i++ )
    {
        uint32_t bit =  ( ( ( uint32_t )1 << ( CHAR_BIT - 1 - ( mask & 0xf ) ) ) & c ) != 0;
        result |= bit << i;
        mask >>= 4;
    }

    return ( char )result;
}

int main( void )
{
    uint32_t mask = 0x64752031;
    char c = 'H';

    printf( "c = %hhx\n", c );

    c = encode( c, mask );

    printf( "c = %hhx\n", c );
}

Вывод программы равен

c = 48
c = 41
1 голос
/ 25 июня 2019

Просто сдвиньте биты в правильные положения.После некоторого веселья, я думаю, у меня есть это:

#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <limits.h>
#include <stdint.h>

/**
 * A little helper function
 * get the bit number 'as' from the byte 'in'
 * and put that bit as the number 'num' in the output
 */
static inline
uint8_t map_get_bit_as(uint8_t in, 
  uint8_t num, uint8_t as)
{
  return (!!(in & (1 << as))) << num;
}

uint8_t map(unsigned long mapping, uint8_t in) 
{
  // static_assert(CHAR_BIT == 8, "are you insane?");

  const int bit0 = mapping / 10000000 % 10;
  const int bit1 = mapping / 1000000 % 10;
  const int bit2 = mapping / 100000 % 10;
  const int bit3 = mapping / 10000 % 10;
  const int bit4 = mapping / 1000 % 10;
  const int bit5 = mapping / 100 % 10;
  const int bit6 = mapping / 10 % 10;
  const int bit7 = mapping / 1 % 10;

  return
    map_get_bit_as(in, 0, bit0) |
    map_get_bit_as(in, 1, bit1) |
    map_get_bit_as(in, 2, bit2) |
    map_get_bit_as(in, 3, bit3) |
    map_get_bit_as(in, 4, bit4) |
    map_get_bit_as(in, 5, bit5) |
    map_get_bit_as(in, 6, bit6) |
    map_get_bit_as(in, 7, bit7);
}

int main() {
  printf("%#02x %#02x\n\n", 'H', map(64752031, 'H'));
}

будет выводить:

0x48 0x41

проверено на repl .

1 голос
/ 25 июня 2019

Используйте побитовые операторы.

Вот пример того, как переместить второй бит в седьмой бит:

x |= (x & 1<<1) << 6;
x &= ~(1<<1);

Если моя битовая нумерация кого-то беспокоит, извините. Именно так я читаю двоичные числа.

Вы также можете поместить это во встроенную функцию:

inline int bit_mode(int *x, int bit1, int bit2)
{
    *x |= *x & (1<<(bit1-1)) << (bit2-1);
    *x &= ~(1<<(bit1-1));
    return *x;
}

int a;
bit_mode(&a, 2, 7);
...