Преобразовать массив байтов в набор битов
Вопрос
У меня есть массив байтов, сгенерированный генератором случайных чисел.Я хочу поместить это в набор бит STL.
К сожалению, похоже, что Bitset поддерживает только следующие конструкторы:
- Строка из 1 и 0, подобная "10101011"
- Неподписанный длинный.(мой массив байтов будет длиннее)
Единственное решение, о котором я могу сейчас подумать, - это прочитать массив байтов побитно и составить строку из 1 и 0.Есть ли у кого-нибудь более эффективное решение?
Решение
Что-то вроде этого?(Не уверен, работает ли здесь магия шаблонов так, как я ожидал.Я заржавел в 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-й конструктор для bitset<>
- он не принимает параметров и устанавливает все биты равными 0.Я думаю, вам нужно будет использовать это, а затем пройти через вызов массива set()
для каждого бита в массиве байтов это равно 1.
Немного грубой силы, но это сработает.Будет немного сложнее преобразовать индекс байта и битовое смещение внутри каждого байта в индекс набора битов, но это ничего, что немного подумав (и, возможно, выполнив в отладчике), не решит.Я думаю, что это, скорее всего, проще и эффективнее, чем пытаться запустить массив с помощью преобразования строки или потока.
Ребята, я потратил много времени на написание обратной функции (bitset -> массив byte / char).Вот оно:
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")
Ну, давайте будем честны, мне было скучно, и я начал думать, что должен быть немного более быстрый способ, чем настройка каждого бита.
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 элементов (в зависимости от ваших флагов оптимизации, переданных компилятору).Больший массив, чем этот, и время, затрачиваемое на сдвиг набора битов, ускоряют настройку каждого бита.
вы можете инициализировать набор битов из потока.Я не могу вспомнить, как вставить байт[] в поток, но...
От 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;
}
Вот моя реализация с использованием шаблонного метапрограммирования.
Циклы выполняются во время компиляции.
Я взял версию @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);