[英]Efficient way to test bits in a byte array using a union?
I have data that is sometimes best viewed as an array of 10 bytes, sometimes as an array of 80 bits.我的数据有时最好被视为一个 10 字节的数组,有时是一个 80 位的数组。 Maybe a job for a union?
也许是工会的工作?
After filling the array with 10 bytes, I scan through the 80 bits and test if set.用 10 个字节填充数组后,我扫描 80 位并测试是否设置。 The scan is advanced bit-by-bit in an ISR, so efficiency is key.
在 ISR 中,扫描是逐位推进的,因此效率是关键。
Right now I do this at each interrupt:现在我在每次中断时都这样做:
volatile uint8_t bit_array[10]; // external to ISR
volatile uint8_t bit_idx;
volatile uint8_t byte_idx;
// -----ISR---------
static uint8_t abyte; // temp byte from array
if (bit_idx == 0) { // at each new byte
bit_idx = 1; // begin at the lowest bit
abyte = bit_array[byte_idx];
}
if (abyte & bit_idx) {
// << do the thing >>
}
if ((bit_idx *= 2) == 0) { // idx << and test for done
if (++byte_idx > 9) { // try next byte
byte_idx = 0;
fill_array_again();
}
}
I have a sense that there's a way to create a union that would allow a straightforward scan of the bits using a single index 0..79, but I don't know enough to try it.我有一种感觉,有一种方法可以创建一个联合,允许使用单个索引 0..79 直接扫描位,但我不太了解尝试它。
The questions are: can I do that?问题是:我可以这样做吗? and: can it be efficient?
并且:它可以有效吗?
You can use the 0 ... 79
range for your index without the need for a union 1 .您可以使用
0 ... 79
范围作为索引,而无需联合1 。 You can get the byte index in your array using index / 8
and the bit position (within that byte) using index % 8
.您可以使用
index / 8
获取数组中的字节索引,使用index % 8
获取位位置(在该字节内)。
This would certainly simplify your code;这肯定会简化您的代码; however, whether it will be significantly more efficient will depend on a number of factors, like what the target CPU is and how smart your compiler is.
但是,它是否会显着提高效率将取决于许多因素,例如目标 CPU 是什么以及编译器的智能程度。 But note that the division and remainder operations with
8
as their RHS are trivial for most compilers/architectures and reduce to a bit-shift and a simple mask, respectively.但请注意,对于大多数编译器/架构来说,以
8
作为 RHS 的除法和余数运算是微不足道的,并且分别减少为位移位和简单掩码。
Here's a possible outline implementation:这是一个可能的大纲实现:
uint8_t data[10]; // The 10 bytes
uint8_t index = 0; // index of bits in 0 .. 79 range
void TestISR()
{
// Test the indexed bit using combination of division and remainder ...
if (data[index / 8] & (1 << (index % 8))) {
// Do something
}
// Increment index ...
if (++index > 79) {
index = 0;
refill_array();
}
}
For any compiler that fails to implement the optimized division and remainder operations, the if
statement can be re-written thus:对于任何未能实现优化除法和余数运算的编译器,可以重写
if
语句:
if (data[index >> 3] & (1 << (index & 7))) {
// ...
1 Note that any attempt to actually use a union will likely exhibit undefined behaviour. 1请注意,任何实际使用联合的尝试都可能表现出未定义的行为。 In C++, reading from a member of a union that wasn't the last one written is UB (although it's acceptable and well-defined in C).
在 C++ 中,从不是最后一个写入的联合成员中读取的是 UB(尽管它在 C 中是可以接受且定义明确的)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.