C++ 如何从 8 个布尔值中创建一个字节(反之亦然)?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8461126/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to create a byte out of 8 bool values (and vice versa)?
提问by xcel
I have 8 bool
variables, and I want to "merge" them into a byte.
我有 8 个bool
变量,我想将它们“合并”成一个字节。
Is there an easy/preferred method to do this?
有没有一种简单/首选的方法来做到这一点?
How about the other way around, decoding a byte into 8 separate boolean values?
反过来,如何将一个字节解码为 8 个单独的布尔值?
I come in assuming it's not an unreasonable question, but since I couldn't find relevant documentation via Google, it's probably another one of those "nonono all your intuition is wrong" cases.
我假设这不是一个不合理的问题,但由于我无法通过谷歌找到相关文档,这可能是另一种“你的直觉是错误的”案例。
采纳答案by rodrigo
The hard way:
艰难的方式:
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;
}
And:
和:
void FromByte(unsigned char c, bool b[8])
{
for (int i=0; i < 8; ++i)
b[i] = (c & (1<<i)) != 0;
}
Or the cool way:
或者很酷的方式:
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;
};
Then you can assign to one member of the union and read from another. But note that the order of the bits in Bits
is implementation defined.
然后您可以分配给联合的一个成员并从另一个成员读取。但请注意,位的顺序Bits
是实现定义的。
回答by Lalaland
You might want to look into std::bitset
. It allows you to compactly store booleans as bits, with all of the operators you would expect.
您可能想查看std::bitset
. 它允许您使用您期望的所有运算符将布尔值紧凑地存储为位。
No point fooling around with bit-flipping and whatnot when you can abstract away.
当您可以抽象时,就没有必要在位翻转之类的东西上胡闹。
回答by Jeremy Friesner
#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);
}
回答by phuclv
The cool way (using the multiplication technique)
很酷的方式(使用乘法技术)
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;
}
Assuming sizeof(bool) == 1
假设 sizeof(bool) == 1
Of course you may need to make sure that the bool array is correctly 8-byte aligned to avoid performance shoot down and/or UB
当然,您可能需要确保 bool 数组正确 8 字节对齐,以避免性能下降和/或 UB
How they work
它们是如何工作的
Suppose we have 8 bools b[0]
to b[7]
whose least significant bits are named a-h respectively that we want to pack into a single byte. Treating those 8 consecutive bool
s as one 64-bit word and load them we'll get the bits in reversed order in a little-endian machine. Now we'll do a multiplication (here dots are zero bits)
假设我们有 8 个布尔值b[0]
,它们b[7]
的最低有效位分别命名为 ah,我们想将它们打包成一个字节。将这 8 个连续的bool
s 视为一个 64 位字并加载它们,我们将在小端机器中以相反的顺序获得这些位。现在我们将进行乘法运算(这里的点是零位)
| b7 || b6 || b4 || b4 || b3 || b2 || b1 || b0 |
.......h.......g.......f.......e.......d.......c.......b.......a
× 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
The arrows are added so it's easier to see the position of the set bits in the magic number. At this point 8 least significant bits has been put in the top byte, we'll just need to mask the remaining bits out
添加了箭头,以便更容易看到幻数中设置位的位置。此时 8 个最低有效位已放入最高字节,我们只需要将其余位屏蔽掉
So the magic number for packing would be 0b1000000001000000001000000001000000001000000001000000001000000001
or 0x8040201008040201
. If you're on a big endian machine you'll need to use the magic number 0x0102040810204080
which is calculated in a similar manner
所以包装的神奇数字是0b1000000001000000001000000001000000001000000001000000001000000001
or 0x8040201008040201
。如果您使用的是大端机器,则需要使用0x0102040810204080
以类似方式计算的幻数
For unpacking we can do a similar multiplication
对于解包,我们可以做一个类似的乘法
| b7 || b6 || b4 || b4 || b3 || b2 || b1 || b0 |
abcdefgh
× 1000000001000000001000000001000000001000000001000000001000000001
────────────────────────────────────────────────────────────────
= h0abcdefgh0abcdefgh0abcdefgh0abcdefgh0abcdefgh0abcdefgh0abcdefgh
& 1000000010000000100000001000000010000000100000001000000010000000
────────────────────────────────────────────────────────────────
= h0000000g0000000f0000000e0000000d0000000c0000000b0000000a0000000
After multiplying we have the needed bits at the most significant positions, so we need to mask out irrelevant bits and shift the remaining ones to the least significant positions. The output will be the bytes contain a to h in little endian.
相乘后,我们在最重要的位置有了所需的位,因此我们需要屏蔽掉不相关的位并将剩余的位移到最不重要的位置。输出将是包含 a 到 h 的小端字节。
The efficient way
有效的方式
On newer x86 CPUs with BMI2there are PEXTand PDEPinstructions for this purpose. The pack8bools
function above can be replaced with
在与新的x86 CPU BMI2有PEXT和PDEP用于此目的的说明。pack8bools
上面的函数可以替换为
_pext_u64(*((uint64_t*)a), 0x0101010101010101ULL);
And the unpack8bools
function can be implemented as
该unpack8bools
功能可以实现为
_pdep_u64(b, 0x0101010101010101ULL);
Unfortunately those instructions are very slow on AMDso you may need to compare with the multiplication method above to see which is better
不幸的是,这些指令在 AMD 上非常慢,因此您可能需要与上面的乘法方法进行比较,看看哪个更好
回答by 111111
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
although you are probably better off using a bitset
虽然你可能最好使用位集
回答by ScarletAmaranth
There is no way to pack 8 bool
variables into one byte. There is a way packing 8 logical true/false states in a single byte using Bitmasking.
没有办法将 8 个bool
变量打包成一个字节。有一种方法可以使用Bitmasking在单个字节中打包 8 个逻辑真/假状态。
回答by iBug
I'd like to note that type punning through union
s is UB in C++ (as rodrigodoes in his answer. The safest way to do that is memcpy()
我想指出,union
在 C++ 中,通过s 进行双关的类型是 UB(正如罗德里戈在他的回答中所做的那样。最安全的方法是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;
}
As others have said, the compiler is smart enough to optimize out memcpy()
.
正如其他人所说,编译器足够聪明,可以优化出memcpy()
.
BTW, this is the way that Boost does type punning.
顺便说一句,这就是 Boost 进行类型双关的方式。
回答by Fabián Heredia Montiel
You would use the bitwise shift operation and casting to archive it. a function could work like this:
您将使用按位移位操作和强制转换来存档它。一个函数可以这样工作:
unsigned char toByte(bool *bools)
{
unsigned char byte = ##代码##;
for(int i = 0; i < 8; ++i) byte |= ((unsigned char) bools[i]) << i;
return byte;
}
Thanks Christian Raufor the correction s!
感谢基督教劳的修正小号!