如何将位序列转换为字节(C/C++)

5

我有几个整数,例如(二进制表示):

00001000、01111111、10000000、00000001

我需要将它们按顺序放入字节数组中,不包括前导零,如下所示:

10001111 11110000 0001000

我知道这必须通过位移和使用二进制或运算符 | 完成。但我找不到正确的算法,请问您能否建议最佳方法?

我需要放置在其中的整数是无符号长整型,因此其长度可以从1位到8字节(64位)。


4
请明确说明您的输入内容、外观、类型以及输出内容、外观和类型。目前描述还不够清晰。 - orlp
输入是任意值的无符号长长整数,输出是一个char *数组(字节数组)。我需要将输出写入文件,因此需要将其转换为字节。 - Smaug
由于字节序的原因,您现在必须指定如何存储数据,并且必须按字节级别进行存储,而不能混合使用字节和长整型。 - Joachim Isaksson
输入和输出都是大端字节序。 - Smaug
4个回答

4
你可以使用 std::bitset 来实现:
#include <bitset>
#include <iostream>

int main() {
    unsigned i = 242122534;
    std::bitset<sizeof(i) * 8> bits;
    bits = i;
    std::cout << bits.to_string() << "\n";
}

这很不错,结合下面我的答案中的trim_right()函数示例,可能是最简单的解决方案。 - Chad

1

当然还有其他的方法,但我可能会选择最简单的方法:

std::vector<unsigned char> integers; // Has your list of bytes
integers.push_back(0x02);
integers.push_back(0xFF);
integers.push_back(0x00);
integers.push_back(0x10);
integers.push_back(0x01);
std::string str;                     // Will have your resulting string
for(unsigned int i=0; i < integers.size(); i++)
    for(int j=0; j<8; j++)
        str += ((integers[i]<<j) & 0x80 ? "1" : "0");
std::cout << str << "\n";
size_t begin = str.find("1");
if(begin > 0) str.erase(0,begin);
std::cout << str << "\n";

在你提到使用长整型或其他类型之前,我已经写好了这个,但实际上这并没有改变很多。掩码需要更改,j循环变量也需要更改,但除此之外,以上代码应该可以工作。


0

将它们转换为字符串,然后删除所有前导零:

#include <iostream>
#include <sstream>
#include <string>
#include <cstdint>

std::string to_bin(uint64_t v)
{
   std::stringstream ss;

   for(size_t x = 0; x < 64; ++x)
   {
       if(v & 0x8000000000000000)
          ss << "1";
       else
          ss << "0";

        v <<= 1;
   }

   return ss.str();
}

void trim_right(std::string& in)
{
   size_t non_zero = in.find_first_not_of("0");

   if(std::string::npos != non_zero)
      in.erase(in.begin(), in.begin() + non_zero);
   else
   {
       // no 1 in data set, what to do?
       in = "<no data>";
   }
}

int main()
{
  uint64_t v1 = 437148234;
  uint64_t v2 = 1;
  uint64_t v3 = 0;

  std::string v1s = to_bin(v1);
  std::string v2s = to_bin(v2);
  std::string v3s = to_bin(v3);

  trim_right(v1s);
  trim_right(v2s);
  trim_right(v3s);

  std::cout << v1s << "\n"
            << v2s << "\n"
            << v3s << "\n";

  return 0;
}

0
一个简单的方法是使用“当前字节”(以下为acc),其中包含已使用位数的相关数字(bitcount)和完全处理过的字节向量(output):
int acc = 0;
int bitcount = 0;
std::vector<unsigned char> output;

void writeBits(int size, unsigned long long x)
{
    while (size > 0)
    {
        // sz = How many bit we're about to copy
        int sz = size;

        // max avail space in acc
        if (sz > 8 - bitcount) sz = 8 - bitcount;

        // get the bits
        acc |= ((x >> (size - sz)) << (8 - bitcount - sz));

        // zero them off in x
        x &= (1 << (size - sz)) - 1;

        // acc got bigger and x got smaller
        bitcount += sz;
        size -= sz;

        if (bitcount == 8)
        {
            // got a full byte!
            output.push_back(acc);
            acc = bitcount = 0;
        }
    }
}

void writeNumber(unsigned long long x)
{
    // How big is it?
    int size = 0;
    while (size < 64 && x >= (1ULL << size))
        size++;
    writeBits(size, x);
}

请注意,在处理结束时,您应该检查累加器中是否仍有任何位(bitcount > 0),如果是,则通过执行output.push_back(acc);来刷新它们。
另请注意,如果速度是一个问题,那么使用更大的累加器可能是一个好主意(但输出将取决于机器的字节序),并且发现一个数字中使用了多少位可以比在C++中进行线性搜索快得多(例如x86有一个专门用于此目的的机器语言指令BSR)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接