Как поместить битовую последовательность в байты (C / C ++) - PullRequest
5 голосов
/ 10 марта 2012

У меня есть пара целых чисел, например (в двоичном представлении):

00001000, 01111111, 10000000, 00000001

, и мне нужно поместить их последовательно в массив байтов (chars), без начальных нулей, например:

10001111 11110000 0001000

Я понимаю, что это должно быть сделано путем сдвига битов с помощью <<, >> и использования двоичного или |.Но я не могу найти правильный алгоритм, можете ли вы предложить лучший подход?

Целые числа, которые мне нужно поставить, это длинные беззнаковые целые числа без знака, поэтому длина одного может быть где угодно от 1 бита до 8 байт(64 бита).

Ответы [ 4 ]

4 голосов
/ 10 марта 2012

Вы можете использовать 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";
}
1 голос
/ 10 марта 2012

Несомненно, есть другие способы сделать это, но я бы, наверное, выбрал самое простое:

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 голосов
/ 10 марта 2012

Простой подход состоит в том, чтобы иметь «текущий байт» (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, предназначенную для этого).

0 голосов
/ 10 марта 2012

Преобразуйте их в строки, затем удалите все начальные нули:

#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;
}
...