Преобразовать байтовый массив в битовый набор - PullRequest
6 голосов
/ 02 апреля 2009

У меня есть байтовый массив, сгенерированный генератором случайных чисел. Я хочу поместить это в набор битов STL.

К сожалению, похоже, что Bitset поддерживает только следующие конструкторы:

  1. Строка из 1 и 0, как "10101011"
  2. Длинный без знака. (мой байтовый массив будет длиннее)

Единственное решение, которое я могу придумать сейчас, - это прочитать битовый массив побитно и создать строку из 1 и 0. У кого-нибудь есть более эффективное решение?

Ответы [ 6 ]

7 голосов
/ 02 апреля 2009

Как то так? (Не уверен, что магия шаблонов работает здесь так, как я ожидал. Я ржавый в C ++.)

std::bitset bytesToBitset<int numBytes>(byte *data)
{
    std::bitset<numBytes * CHAR_BIT> b;

    for(int i = 0; i < numBytes; ++i)
    {
        byte cur = data[i];
        int offset = i * CHAR_BIT;

        for(int bit = 0; bit < CHAR_BIT; ++bit)
        {
            b[offset] = cur & 1;
            ++offset;   // Move to next bit in b
            cur >>= 1;  // Move to next bit in array
        }
    }

    return b;
}
3 голосов
/ 02 апреля 2009

3-й конструктор для bitset<> - он не принимает параметров и устанавливает все биты на 0. Я думаю, вам нужно использовать это, а затем пройтись по массиву, вызывая set() для каждого бита в байтовом массиве, который 1.

Немного грубой силы, но это сработает. Будет немного сложнее преобразовать индекс байта и смещение битов в каждом байте в индекс набора битов, но это ничто, так что немного подумать (и, возможно, пробежаться под отладчиком) не решит. Я думаю, что это, скорее всего, проще и эффективнее, чем пытаться запустить массив с помощью преобразования строк или потока.

2 голосов
/ 09 марта 2011

Хорошо, давайте будем честными, мне стало скучно, и я начал думать, что должен быть способ немного быстрее, чем устанавливать каждый бит.

template<int numBytes>
std::bitset<numBytes * CHARBIT bytesToBitset(byte *data)
{
    std::bitset<numBytes * CHAR_BIT> b = *data;

    for(int i = 1; i < numBytes; ++i)
    {
        b <<= CHAR_BIT;  // Move to next bit in array
        b |= data[i];    // Set the lowest CHAR_BIT bits
    }

    return b;
}

Это действительно немного быстрее, по крайней мере до тех пор, пока байтовый массив меньше 30 элементов (в зависимости от ваших флагов оптимизации, передаваемых компилятору). Массив большего размера, чем это, и время, используемое для сдвига набора битов, ускоряют установку каждого бита.

2 голосов
/ 25 апреля 2010

Ребята, я потратил много времени на написание обратной функции (bitset -> byte / char array). Вот оно:

    bitset<SIZE> data = ...

    // bitset to char array
    char current = 0;
    int offset = 0;
    for (int i = 0; i < SIZE; ++i) {
        if (data[i]) { // if bit is true
            current |= (char)(int)pow(2, i - offset * CHAR_BIT); // set that bit to true in current masked value
        } // otherwise let it to be false
        if ((i + 1) % CHAR_BIT == 0) { // every 8 bits
            buf[offset++] = current; // save masked value to buffer & raise offset of buffer
            current = 0; // clear masked value
        }
    }

    // now we have the result in "buf" (final size of contents in buffer is "offset")
0 голосов
/ 24 мая 2016

Вот моя реализация с использованием шаблонного метапрограммирования.
Циклы выполняются во время компиляции.
Я взял версию @strager, изменил ее, чтобы подготовиться к TMP:

  • изменил порядок итерации (чтобы я мог сделать из него рекурсию);
  • уменьшено количество используемых переменных.

Модифицированная версия с циклами во время выполнения:

template <size_t nOfBytes>
void bytesToBitsetRunTimeOptimized(uint8_t* arr, std::bitset<nOfBytes * CHAR_BIT>& result) {
  for(int i = nOfBytes - 1; i >= 0; --i) {
    for(int bit = 0; bit < CHAR_BIT; ++bit) {
      result[i * CHAR_BIT + bit] = ((arr[i] >> bit) & 1);
    }
  }
}

Версия TMP на его основе:

template<size_t nOfBytes, int I, int BIT> struct LoopOnBIT {
  static inline void bytesToBitset(uint8_t* arr, std::bitset<nOfBytes * CHAR_BIT>& result) {
    result[I * CHAR_BIT + BIT] = ((arr[I] >> BIT) & 1);
    LoopOnBIT<nOfBytes, I, BIT+1>::bytesToBitset(arr, result);
  }
};
// stop case for LoopOnBIT
template<size_t nOfBytes, int I> struct LoopOnBIT<nOfBytes, I, CHAR_BIT> {
  static inline void bytesToBitset(uint8_t* arr, std::bitset<nOfBytes * CHAR_BIT>& result) { }
};

template<size_t nOfBytes, int I> struct LoopOnI {
  static inline void bytesToBitset(uint8_t* arr, std::bitset<nOfBytes * CHAR_BIT>& result) {
    LoopOnBIT<nOfBytes, I, 0>::bytesToBitset(arr, result);
    LoopOnI<nOfBytes, I-1>::bytesToBitset(arr, result);
  }
};
// stop case for LoopOnI
template<size_t nOfBytes> struct LoopOnI<nOfBytes, -1> {
  static inline void bytesToBitset(uint8_t* arr, std::bitset<nOfBytes * CHAR_BIT>& result) { }
};

template <size_t nOfBytes>
void bytesToBitset(uint8_t* arr, std::bitset<nOfBytes * CHAR_BIT>& result) {
  LoopOnI<nOfBytes, nOfBytes - 1>::bytesToBitset(arr, result);
}

код клиента:

uint8_t arr[]={0x6A};
  std::bitset<8> b; 
  bytesToBitset<1>(arr,b);
0 голосов
/ 02 апреля 2009

вы можете инициализировать набор битов из потока. Я не могу вспомнить, как втиснуть байт [] в поток, но ...

от http://www.sgi.com/tech/stl/bitset.html

  bitset<12> x;

  cout << "Enter a 12-bit bitset in binary: " << flush;
  if (cin >> x) {
    cout << "x =        " << x << endl;
    cout << "As ulong:  " << x.to_ulong() << endl;
    cout << "And with mask: " << (x & mask) << endl;
    cout << "Or with mask:  " << (x | mask) << endl;
  }
...