简体   繁体   中英

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. Maybe a job for a union?

After filling the array with 10 bytes, I scan through the 80 bits and test if set. The scan is advanced bit-by-bit in an ISR, so efficiency is key.

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.

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 . You can get the byte index in your array using index / 8 and the bit position (within that byte) using 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. 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.

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 (data[index >> 3] & (1 << (index & 7))) {
        // ...

1 Note that any attempt to actually use a union will likely exhibit undefined behaviour. 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).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM