重新索引一个字符内的位

时间:2019-06-25 15:42:07

标签: c bit-manipulation bit-shift

我有一个练习,我必须按照命令行给出的位级别对字符串进行编码和解码。

需要注意的是,我必须使用置换映射来对位进行重新排序。

这是一个例子:

用户输入要编码的字符

 H

H的二进制是

 01001000 

但是,这是8位到0-7的常规映射。

我的程序必须将这些位置换为我使用的任何映射模式。

例如,如果我使用映射64752031

字符'H'的位

01001000 

转到

01000001

编码char时,第0位变为第6位,第2位变为第4位,第3位变为第7位,依此类推。不论该映射基于什么。

有没有一种方法可以根据给定的排列图来操纵和更改位的顺序?

谢谢。

4 个答案:

答案 0 :(得分:3)

如果您需要处理较大的字符串,最好使用可以预先计算翻译的查找表。

#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上以映射给出的逻辑权重将其设置为1。通过对单元格i的内容正确移位1进行设置。

答案 1 :(得分:1)

使用按位运算符。

这是一个如何将第二位移到第七位的示例:

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);

答案 2 :(得分:1)

只需将位移到正确的位置。经过一番乐趣之后,我想我已经明白了:

#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上进行了测试。

答案 3 :(得分:1)

如果我在对它们进行计数时正确理解了位的顺序,那么相应功能可以按照演示程序中所示的方式进行查找。

#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