【问题标题】:Looping over bits in C循环C中的位
【发布时间】:2018-06-17 16:14:32
【问题描述】:

我是 C 新手,我想根据以下过程将输入位存储到输出数组中。

input           MSB                  LSB MSB                  LSB MSB              
[169,48,0] =     1  0  1  0  1  0  0  1   0  0  1  1  0  0  0  0   0  0  0  0  0  0  0  0 

程序应遍历输入数据以查找起始索引存在于哪个字节中,并提取从起始索引到结束索引的位并将其存储在输出[]中。例如,我的起始索引是 4,它存在于 input[0] 中,我的结束索引是 13。所以我需要从位位置 4 提取到 13 并将其放在 output[] 中。

当我说位位置 4 到 13 时,我的意思是 - 我需要来自 input[0] 的 bits[4 - 7] = {0 1 0 0 1} 和 bits[8 - 13] = {1 1 0 0 0 0} 来自输入[1]

expected
output
[9, 48,0] =     0  0  0  0  1  0  0  1   0  0  1  1  0  0  0  0   0  0  0  0  0  0  0  0

我尝试用 C 编程,但不幸的是我没有成功,位循环是通过 LSB 到 MSB。我需要遍历第一个字节并继续到下一个字节并重复直到存在结束位置的字节索引。

#include<stdio.h>
int main()
{
    unsigned char input[3] = {169,48,0};
    unsigned char output[3]= {0};
    int i, start = 4, end = 13;
    for(i=0; i<3; i++)
    {
        output[i] = (input[i] >> (start)) & ((1u << (end)) -1u);
        printf("%u\n",output[i]);
    }
    return 0;
}

程序循环遍历所有 3 个输入字节,并从位索引 4 存储到该特定字节的结束索引,即 7。

output
[10, 3, 0] =     0  0  0  0  1  0  1  0   0  0  0  0  0  0  1  1   0  0  0  0  0  0  0  0 

我想检查我的起始索引是否存在于 input[0] 或 input[1] 或 . . . input[n],根据开头显示的预期输出,从起始索引复制并存储到结束索引(可能存在于任何字节位置)。

如果你能纠正程序逻辑,我会很高兴,因为我是 C 新手。

【问题讨论】:

  • 您认为位 0 是数组的哪一端,我无法确定预期的输出。如果位 0 是右侧字节的 LSB,则位 3-11 都是0,输出应该都是0。如果位 0 是左侧字节的 LSB,我仍然无法弄清楚,因为输出位 0 是 1,而您说您忽略了该位。
  • 如果您要提取的位数始终为 8(如您的示例中所示),则此问题让人想起计算 8 位 CRC。但我认为您想移动 任意 位数 - 对吗?
  • this的一些变体
  • @DavidCollins 不,它并不总是 8 位。我需要提取任意数量的位。

标签: c


【解决方案1】:

欢迎来到论坛。

如果你能纠正程序逻辑,我会很高兴,因为我是 C 新手。

这是一个试探性的尝试。您的主要逻辑在以下行:

output[i] = (input[i] >> (start)) & ((1u << (end)) -1u);

通过将其简化为以下形式(并使用临时的unsigned char 变量tmp)更容易分析:

tmp = input[i] >> start; // (1)
tmp &= (1u << end) - 1u; // (2)
// etc.

我不清楚你在这里想要做什么。我相信您应该尝试做的是从input[i] 中提取8-start 位和从input[i+1] 中提取start 位,并将这些值的逻辑或(适当移位)放在临时多变的。如果是这样,那么我的建议如下。

在第一行 (1) 中,您移动了错误的方向:应该是

tmp = input[i] << start;

下一行 (2) 没有完成任何事情。 (您实际上是与零进行与运算。)此外,您应该使用 |而不是 &,并且第二个操作数应该是从下一个字节开始选择的位(适当地移位)。

tmp |= input[i+1] >> (8-start);

这就是提取阶段。接下来是输出流中的 insertion 阶段。上面没有讨论更多的细微差别,但这给出了总体思路。 (有关处理更多细节的实现,请参见下文。)

我想检查我的起始索引是否存在于 input[0] 或 input[1] 或 . . .输入[n]

为了这个用途

int idx = start / 8; // byte index
int offset = start % 8; // bit position within byte

P.S. 您最初的问题表明,在输出流中提取位的偏移量可能与在输入流中不同。您的编辑隐藏了这一事实,但下面的实现允许这种可能性(“转置”)。

可能的实现

void transpose_bits(unsigned char *a, unsigned char *b, int start, int end, int dest, size_t array_len) {
    unsigned char tmp = '\0', tmp2 = '\0';
    int offset = 0, idx = 0, len = 0, next_bits = 0;
    char bitmask = 0x80;

    len = end - start;
    while (len > 0) {
        // Single pass - transpose up to 8 bits ...
        tmp = tmp2 = '\0';

        // Determine the byte index and offset in the input byte array.
        idx = start / 8;
        offset = start % 8;
        tmp = a[idx] << offset;
        next_bits = offset + len - 8;
        if (next_bits < 0) {
            // Don't even need all of current byte  => remove trailing bits ...
            tmp &= bitmask >> (len - 1);
        } else if (next_bits > 0) {
            // Need to include part of next byte ...
            tmp2 = a[idx + 1] & (bitmask >> (next_bits - 1));
            tmp |= tmp2 >> (8 - offset);
        }

        // Determine byte index and offset in output byte array
        idx = dest / 8;
        offset = dest % 8;
        b[idx] |= tmp >> offset;
        b[idx + 1] |= tmp << (8 - offset);
        // Update start position and length for next pass ...
        if (len > 8) {
            len -= 8;
            dest += 8;
            start += 8;
        } else
            len -= len;
    }
}

示例用法:

// Extract bits: 'start' and 'dest' are the same.
transpose_bits(input, output, 4, 13, 4, 3); // Assume arrays are of length '3'

// Transpose bits: 'start' and 'dest' not the same.
transpose_bits(input, output, 4, 13, 10, 3);

注意事项

  • char[] 数组必须是无符号的(正如您正确选择的那样) - 因为右移运算符对有符号值的工作方式不同。
  • 您应该检查数组的边界(比较idxarray_len);为简洁起见,我在这里跳过了
  • transpose_bits() 函数的while() 循环中的每次迭代最多可以处理 8 位。通过使用多次传递,它可以处理任意数量。

【讨论】:

  • 这有帮助。非常感谢您的详细解释。不幸的是,由于我没有足够的声誉,因此我无法赞成这个答案。
  • @shannon:没问题。感谢您的反馈。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-01-05
  • 1970-01-01
  • 2013-11-05
  • 1970-01-01
  • 1970-01-01
  • 2014-03-06
  • 1970-01-01
相关资源
最近更新 更多