【问题标题】:Shifting arrays of bytes and skipping bits移位字节数组和跳过位
【发布时间】:2015-09-11 12:41:55
【问题描述】:

我正在尝试创建一个函数,该函数将返回给定内存块的N 位数,并可选择跳过M 位。

例子:

unsigned char *data = malloc(3);
data[0] = 'A'; data[1] = 'B'; data[2] = 'C';
read(data, 8, 4);

会跳过 12 位,然后从数据块“ABC”中读取 8 位。

“跳过”位意味着它实际上会对整个数组进行位移,从右到左携带位。

在这个例子中ABC

01000001 01000010 01000011

函数需要返回

    0001 0100

这个问题是my previous question的后续问题

Minimal compilable code

#include <ios>
#include <cmath>
#include <bitset>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>

using namespace std;

typedef unsigned char byte;
typedef struct bit_data {
    byte *data;
    size_t length;
} bit_data;

/*
   Asume skip_n_bits will be 0 >= skip_n_bits <= 8
*/
bit_data *read(size_t n_bits, size_t skip_n_bits) {
    bit_data *bits = (bit_data *) malloc(sizeof(struct bit_data));

    size_t bytes_to_read = ceil(n_bits / 8.0);
    size_t bytes_to_read_with_skip = ceil(n_bits / 8.0) + ceil(skip_n_bits / 8.0);

    bits->data = (byte *) calloc(1, bytes_to_read);
    bits->length = n_bits;

    /* Hardcoded for the sake of this example*/
    byte *tmp = (byte *) malloc(3);
    tmp[0] = 'A'; tmp[1] = 'B'; tmp[2] = 'C';

    /*not working*/
    if(skip_n_bits > 0){
        unsigned char *tmp2 = (unsigned char *) calloc(1, bytes_to_read_with_skip);
        size_t i;

        for(i = bytes_to_read_with_skip - 1; i > 0; i--) {
            tmp2[i] = tmp[i] << skip_n_bits;
            tmp2[i - 1] = (tmp[i - 1] << skip_n_bits) | (tmp[i] >> (8 - skip_n_bits));
        }

        memcpy(bits->data, tmp2, bytes_to_read);
        free(tmp2);
    }else{
        memcpy(bits->data, tmp, bytes_to_read);
    }
    free(tmp);

    return bits;
}

int main(void) {
    //Reading "ABC"
    //01000001 01000010 01000011
    bit_data *res = read(8, 4);

    cout << bitset<8>(*res->data);
    cout << " -> Should be '00010100'";

    return 0;
}

当前代码返回00000000 而不是00010100。 我觉得错误很小,但我错过了。问题出在哪里?

【问题讨论】:

  • 很难猜出你认为你正在完成将一个字节左移 12 位(以存储在另一个字节中)或右移负 4 位。对于任何类型的一般性,您应该将要跳过的位数划分为要跳过的多个完整字节,然后是要跳过的其他位数(零到七)。
  • 另外,size_t bytes_to_read_with_skip = ceil(n_bits / 8.0) + ceil(skip_n_bits / 8.0); 中的单独 ceil 可以让您“读取”比实际需要的多一个字节。
  • @JSF 哎呀,我把问题搞砸了。我的实际代码处理skip_n_bits &gt; 8。让我更新一下问题。
  • @JSF 这很有趣。现在它起作用了。我想我会删除这个问题并尝试进一步调试我的代码,因为事实证明我什至不知道它在哪里失败。

标签: c++ arrays bit-shift


【解决方案1】:

您的代码被标记为 C++,实际上您已经在使用像 bitset 这样的 C++ 结构,但是它非常类似于 C。我认为要做的第一件事是使用更多的 C++。

结果表明 bitset 已经非常灵活了。我的方法是创建一个来存储我们输入数据中的所有位,然后根据您希望跳过的数字获取其中的一个子集,然后返回该子集:

template<size_t N, size_t M, typename T = unsigned char>
std::bitset<N> read(size_t skip_n_bits, const std::array<T, M>& data)
{
    const size_t numBits = sizeof(T) * 8;

    std::bitset<N> toReturn; // initially all zeros

    // if we want to skip all bits, return all zeros
    if (M*numBits <= skip_n_bits)
        return toReturn;

    // create a bitset to store all the bits represented in our data array
    std::bitset<M*numBits> tmp;

    // set bits in tmp based on data
    // convert T into bit representations
    size_t pos = M*numBits-1;
    for (const T& element : data)
    {
        for (size_t i=0; i < numBits; ++i)
        {
            tmp.set(pos-i, (1 << (numBits - i-1)) & element);
        }
        pos -= numBits;
    }

    // grab just the bits we need
    size_t startBit = tmp.size()-skip_n_bits-1;
    for (size_t i = 0; i < N; ++i)
    {
        toReturn[N-i-1] = tmp[startBit];
        tmp <<= 1;
    }

    return toReturn;
}

Full working demo

现在我们可以这样称呼它:

// return 8-bit bitset, skip 12 bits
std::array<unsigned char, 3> data{{'A', 'B', 'C'}};
auto&& returned = read<8>(12, data);
std::cout << returned << std::endl;

打印

00100100

这正是我们的输入 01000001 01000010 01000011 跳过前 12 位(从左到右),只抓取接下来的 8 位。

我认为这比你所拥有的更容易阅读,尤其是。从 C++ 程序员的角度来看。

【讨论】:

    猜你喜欢
    • 2010-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-21
    • 2021-11-30
    • 2012-08-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多