将字节数组转换为位集
Posted
技术标签:
【中文标题】将字节数组转换为位集【英文标题】:Convert Byte Array into Bitset 【发布时间】:2010-10-17 00:36:29 【问题描述】:我有一个由随机数生成器生成的字节数组。我想把它放入 STL 位集。
不幸的是,Bitset 似乎只支持以下构造函数:
-
由 1 和 0 组成的字符串,例如“10101011”
无符号长整数。 (我的字节数组会更长)
我现在能想到的唯一解决方案是逐位读取字节数组并制作一个由 1 和 0 组成的字符串。有没有人有更有效的解决方案?
【问题讨论】:
【参考方案1】:这样的?
#include <bitset>
#include <climits>
template<size_t numBytes>
std::bitset<numBytes * CHAR_BIT> bytesToBitset(uint8_t *data)
std::bitset<numBytes * CHAR_BIT> b;
for(int i = 0; i < numBytes; ++i)
uint8_t 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;
还有一个用法示例:
int main()
std::array<uint8_t, 4> bytes = 0xDE, 0xAD, 0xBE, 0xEF ;
auto bits = bytesToBitset<bytes.size()>(bytes.data());
std::cout << bits << std::endl;
【讨论】:
【参考方案2】:bitset<>
有第三个构造函数 - 它不接受参数并将所有位设置为 0。我认为您需要使用它,然后遍历数组调用 set()
为字节数组中的每个位1.
有点蛮力,但它会工作。将每个字节内的字节索引和位偏移量转换为位集索引会有一些复杂性,但没有什么想法(也许在调试器下运行)无法解决。我认为这很可能比尝试通过字符串转换或流运行数组更简单、更有效。
【讨论】:
【参考方案3】:伙计们,我花了很多时间编写一个反向函数(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")
【讨论】:
【参考方案4】:这是我使用模板元编程的实现。 循环在编译时完成。 我拿了@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);
【讨论】:
【参考方案5】:好吧,说实话,我很无聊,并开始认为必须有一种比设置每个位更快的方法。
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 个元素(取决于传递给编译器的优化标志)。比这更大的数组和移位位集所用的时间使得设置每个位更快。
【讨论】:
【参考方案6】:您可以从流中初始化位集。我不记得如何将 byte[] 转换为流,但是...
来自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;
【讨论】:
以上是关于将字节数组转换为位集的主要内容,如果未能解决你的问题,请参考以下文章