我有8个bool
变量,我想将它们“合并”成一个字节。
有一种简单/首选的方法吗?
另一种方法是如何将一个字节解码为8个独立的布尔值?
我认为这不是一个不合理的问题,但由于我无法通过谷歌找到相关文档,这可能是另一个“非你所有直觉都是错误的”案例。
答案 0 :(得分:20)
艰难的道路:
unsigned char ToByte(bool b[8])
{
unsigned char c = 0;
for (int i=0; i < 8; ++i)
if (b[i])
c |= 1 << i;
return c;
}
和
void FromByte(unsigned char c, bool b[8])
{
for (int i=0; i < 8; ++i)
b[i] = (c & (1<<i)) != 0;
}
或者很酷的方式:
struct Bits
{
unsigned b0:1, b1:1, b2:1, b3:1, b4:1, b5:1, b6:1, b7:1;
};
union CBits
{
Bits bits;
unsigned char byte;
};
然后您可以分配给联盟的一个成员并从另一个成员读取。但请注意Bits
中位的顺序是实现定义的。
答案 1 :(得分:10)
您可能需要查看std::bitset
。它允许您将布尔值紧凑地存储为位,以及您期望的所有运算符。
当你可以抽象出来时,没有必要愚弄比特翻转等等。
答案 2 :(得分:5)
#include <stdint.h> // to get the uint8_t type
uint8_t GetByteFromBools(const bool eightBools[8])
{
uint8_t ret = 0;
for (int i=0; i<8; i++) if (eightBools[i] == true) ret |= (1<<i);
return ret;
}
void DecodeByteIntoEightBools(uint8_t theByte, bool eightBools[8])
{
for (int i=0; i<8; i++) eightBools[i] = ((theByte & (1<<i)) != 0);
}
答案 3 :(得分:3)
inline uint8_t pack8bools(bool* a)
{
uint64_t t = *((uint64_t*)a);
return 0x8040201008040201*t >> 56;
}
void unpack8bools(uint8_t b, bool* a)
{
auto MAGIC = 0x8040201008040201ULL;
auto MASK = 0x8080808080808080ULL;
*((uint64_t*)a) = ((MAGIC*b) & MASK) >> 7;
}
当然,您可能需要确保bool数组正确对齐了8个字节,以避免性能下降和/或UB
假设我们有8个布尔b[0]
至b[7]
,它们的最低有效位分别命名为a-h,我们希望将其打包为一个字节。将这8个连续的bool
视为一个64位字并加载它们,我们将在Little-endian机器中以相反的顺序获取这些位。现在我们要做一个乘法(这里的点是零位)
| b7 || b6 || b4 || b4 || b3 || b2 || b1 || b0 |
.......h.......g.......f.......e.......d.......c.......b.......a
x 1000000001000000001000000001000000001000000001000000001000000001
▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
↑......h.↑.....g..↑....f...↑...e....↑..d.....↑.c......↑b.......a
↑.....g..↑....f...↑...e....↑..d.....↑.c......↑b.......a
↑....f...↑...e....↑..d.....↑.c......↑b.......a
+ ↑...e....↑..d.....↑.c......↑b.......a
↑..d.....↑.c......↑b.......a
↑.c......↑b.......a
↑b.......a
a
▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
= abcdefghxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
添加了箭头,以便更轻松地查看魔术数字中设置位的位置。此时,最低有效位已放入8个字节,我们只需要屏蔽掉其余位即可
因此打包的魔数将为0b1000000001000000001000000001000000001000000001000000001000000001
或0x8040201008040201
。如果您使用的是大端字节序计算机,则需要使用以类似方式计算的幻数0x0102040810204080
对于拆箱,我们可以进行类似的乘法
| b7 || b6 || b4 || b4 || b3 || b2 || b1 || b0 |
abcdefgh
x 1000000001000000001000000001000000001000000001000000001000000001
__________________________________________________________________
= h0abcdefgh0abcdefgh0abcdefgh0abcdefgh0abcdefgh0abcdefgh0abcdefgh
& 1000000010000000100000001000000010000000100000001000000010000000
__________________________________________________________________
= h0000000g0000000f0000000e0000000d0000000c0000000b0000000a0000000
相乘后,我们在最高有效位置有所需的位,因此我们需要屏蔽掉无关的位并将其余的位移到最低有效的位置。输出将是在小端序中包含a到h的字节。
在带有BMI2的较新x86 CPU上,有PEXT和PDEP条指令用于此目的。上面的pack8bools
函数可以替换为
_pext_u64(*((uint64_t*)a), 0x0101010101010101ULL);
unpack8bools
函数可以实现为
_pdep_u64(b, 0x0101010101010101ULL);
答案 4 :(得分:2)
bool a,b,c,d,e,f,g,h;
//do stuff
char y= a<<7 | b<<6 | c<<5 | d<<4 | e <<3 | f<<2 | g<<1 | h;//merge
尽管你最好使用bitset
答案 5 :(得分:2)
无法将8个bool
变量打包到一个字节中。有一种方法可以使用Bitmasking在一个字节中打包8个逻辑真/假状态。
答案 6 :(得分:0)
您可以使用按位移位操作和强制转换来存档它。一个函数可以像这样工作:
unsigned char toByte(bool *bools)
{
unsigned char byte = \0;
for(int i = 0; i < 8; ++i) byte |= ((unsigned char) bools[i]) << i;
return byte;
}
感谢Christian Rau进行更正 s !
答案 7 :(得分:0)
我想请注意,通过union
的类型惩罚是C ++中的UB(正如 rodrigo 在his answer中所做的那样。最安全的方法是{{} 1}}
memcpy()
正如其他人所说,编译器非常聪明,可以优化struct Bits
{
unsigned b0:1, b1:1, b2:1, b3:1, b4:1, b5:1, b6:1, b7:1;
};
unsigned char toByte(Bits b){
unsigned char ret;
memcpy(&ret, &b, 1);
return ret;
}
。
答案 8 :(得分:-1)
即使使用C ++,我也在使用这个头文件:
#ifndef __bit_h__
#define __bit_h__
#ifdef __cplusplus
#include <cstdint>
extern "C" {
#else
#include <stdint.h>
#endif
#ifndef BITWISE_OPERATIONS_TYPE
#define BITWISE_OPERATIONS_TYPE uint_fast64_t
#endif
// gives a value with only the nth bit set
// usage: int flags = 10000b;
// bool enabled = (flags & BIT(4)) ? true : false; // result is true
#define BIT(n) (((BITWISE_OPERATIONS_TYPE) 1) << (n))
// gives the input with the nth bit set
// usage: flags = BIT_SET(flags, 3);
// result: flags = 0b11000
#define BIT_SET(in, n) (in | BIT(n))
// gives the input with the nth bit clear
// usage: flags = BIT_CLR(flags, 3);
// result: flags = 0b10000
#define BIT_CLR(in, n) (in & ~BIT(n))
// gives the nth bit only of the input
// usage: bool both_clr = !(BIT_GET(flags1, 3) & BIT_GET(flags2, 3));
// result: both_clr = true (lets say `flags1, flags2 = 0, 0`)
#define BIT_GET(in, n) (in & BIT(n))
// gives 1 if the nth bit of the input is set else gives 0
// usage: if(IS_BIT_SET(flags, 3)) { /*... it will not run */ }
#define IS_BIT_SET(in, n) (BIT_GET(in, n) > 0)
static inline BITWISE_OPERATIONS_TYPE bit(unint_fast8_t n) {
return (((BITWISE_OPERATIONS_TYPE) 1) << n); }
static inline BITWISE_OPERATIONS_TYPE bit_set(BITWISE_OPERATIONS_TYPE in, unint_fast8_t n) {
return (in | bit(n)); }
static inline BITWISE_OPERATIONS_TYPE bit_clr(BITWISE_OPERATIONS_TYPE in, unint_fast8_t n) {
return (in & ~bit(n)); }
static inline BITWISE_OPERATIONS_TYPE bit_get(BITWISE_OPERATIONS_TYPE in, unint_fast8_t n) {
return (in & bit(n)); }
static inline unint_fast8_t is_bit_set(BITWISE_OPERATIONS_TYPE in, unint_fast8_t n) {
return (bit_get(in, n) > 0); }
#ifdef __cplusplus
}
#endif
#endif // __bit_h__
简单易懂,没有类定义,您可以根据需要自由修改此文件...例如,您可以将uint_fast64_t
更改为uint_fast32_t
以让编译器使用具有至少32位大小而不是64位的快速访问的适当位置。虽然宏和函数几乎都会产生相同的代码......但这取决于您用来编译此代码的机器的体系结构。
因此,作为问题的解决方案,您实际上可以创建get
和set
方法,如下所示:
bool get(const uint_fast8_t& nth) { // or `const unsigned char&` or `const char&`
return IS_BIT_SET(this->somewhere, nth);
}
void set(const uint_fast8_t& nth) { // or `const unsigned char&` or `const char&`
this->flags = BIT_SET(this->somewhere, nth);
}
这就是pack
和unpack
他们的方式:
static char pack8bit(bool* bools) { // `char` for an 8bit return (output) value and `bool*` for the input 8 bools ... should be unrolled args ?!?!
char buff = 0;
for(unsigned char i = 0; i < 8; ++i)
buff = (bools[i]) ? bit_set(buff, i) : bit_clr(buff, i);
return buff;
}
static void unpack8bit(const char& from, bool* bools) { // `from` for the packed input and `bool*` for the output 8 bools ... should be unrolled args ?!?!
for(unsigned char i = 0; i < 8; ++i)
bools[i] = is_bit_set(from, i) ? true : false;
}
我知道这是一个非常晚的答案......