C 中的位 rearrangement/manipulation

Bit rearrangement/manipulation in C

我想排列一个字节中的位,以产生特定的顺序。例如,如果起始字节如下 0 1 1 0 1 0 1 0,位标记为 1 2 3 4 5 6 7 8,我想对其进行排列,使其与以下位置匹配:2 4 3 5 7 1 8 6 结果为:1 0 1 1 1 0 0 0。最有效的方法是什么?我阅读了 "look-up" 个表格,但我不确定它是如何工作的。有人可以举例说明在 C 中进行这种位重排的有效方法吗?

我想我明白他想要达到的目的。此代码可能对您有所帮助:

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

int main(void) {
  uint8_t original = 0b01101010;
  uint8_t positions[8] = {1,3,2,4,6,0,7,5};
  uint8_t result = 0;

  for(int i = 0; i < 8; i++)
  {   
     if(original & (1 << (7 - positions[i])))
        result |= (1 << (7-i));
  }
 return 0;
}

我做的第一件事是创建一个字节来表示原始值以及要更改的位置的数组。下一步是查看第 x 处的原始字节。位置为零或一,如果是,则移动结果中的值。最后一个 for 循环仅用于打印结果。 我将您的指数调整为从零开始。

您可以创建一个包含 256 个条目的 "unsigned char" 数组。该数组的索引将是要转换的字节的当前值,而该条目的值将是 "converted" 值。

或者,您可以使用位掩码和 "if" 语句...但效率较低。

这是 "array" 方法的一个片段...只定义了几个值... ...并且没有输出 "binary-text" 格式的输出。

#include<stdio.h>

unsigned char lkup[256] =
    { 0x00,            /* idx: 0  (0x00) */
      0x02,            /* idx: 1  (0x01) (0b00000001) */
      0x08,            /* idx: 2  (0x02) (0b00000010) */
      0x0a,            /* idx: 3  (0x03) (0b00000011) */
      0x01             /* idx: 4  (0x04) (0b00000100) */
      };

int main(int argc, char **argv)
{
    unsigned char wk = 3;

    printf("Input: %u  output: >%u\n", wk, lkup[wk]);
}

这是更改位位置的一种方法。使用 & (和运算符)我们 select char 中的某些位,然后将它们移动到新的位位置。最后,所有移位的位都会通过 |(或运算符)愉快地连接在一起。 左移 << 将位向左移动,右移 >> 将位向右移动。我自由地重新编号位位置。 7表示左边的最高有效位,0是最低有效位,所以左右移位操作正确描述了移位方向。

为什么最后两行先是移位运算,然后是与运算? – 因为char类型可以是无符号的,如果我们对负值进行右移,例如11111000 (-8),最高位将被复制; 11111000 >> 2 将导致 (1 filled from this end -->) 11111110 (-2)。 (参见 Right shifting negative numbers in C。)

但回到功能:

char changebitpositions (char ch) {

                                  // bit locations (- = don't care)
                                  // before      after
    return (ch & 0x20)            // --5----- => --5----- (no change)
        | ((ch & 0x49) << 1)      // -6--3--0 => 6--3--0-
        | ((ch & 0x12) << 2)      // ---4--1- => -4--1---
        | ((ch >> 5) & 0x04)      // 7------- => -----7--
        | ((ch >> 2) & 0x01);     // -----2-- => -------2

        // original and result:      76543210 => 64531702
}