0
\$\begingroup\$

I need to access a particular bit from a uint8 variable, and store this bit value to another uint8 variable. Right now I am doing the following to achieve this:

bit_value = (uint8_variable & (1 << BIT_POSITION)) >> BIT_POSITION;

Is this the right method? If it is right, is there a simpler way to achieve this?

Update: One more question. I need to set a particular bit in a uint8 to a value X(not toggling the bit). eg: In 1100 0101, I need to set bit 2 to X, without modifying the other bits - to obtain 1100 0X01. I have been racking my brain, but I can't land on a straight forward solution.

\$\endgroup\$
6
  • \$\begingroup\$ Do you need the actual bit (eg, cast to bit 1 or 0), or just know if it's set or not? \$\endgroup\$
    – Jeroen3
    Oct 10, 2018 at 7:33
  • 2
    \$\begingroup\$ bit_value = ((uint8_variable>>BIT_POSITION)&1) \$\endgroup\$ Oct 10, 2018 at 7:41
  • \$\begingroup\$ You are near the solution. Miss just a bit mask as suggested by user43648 \$\endgroup\$ Oct 10, 2018 at 7:58
  • \$\begingroup\$ @Jeroen3 i need the actual bit value.. \$\endgroup\$
    – stenvar
    Oct 10, 2018 at 8:17
  • \$\begingroup\$ I am still not sure what you want. Should value "10100100" and bit position "2" return "1" or "4"? \$\endgroup\$
    – Rev
    Oct 10, 2018 at 9:00

3 Answers 3

5
\$\begingroup\$

I got an idea, at least I would do it like this. So, bit_value = ((uint8_variable>>BIT_NEEDED)&1) So this would shift the bit you need in LSB position, and the & operator would mask the other bits. Example: uint8_variable = 0110 1010 BIT_NEEDED=3 0110 1010 >> 3 = 0000 1101 0000 1101 & 0000 0001 = 0000 0001

I think this should work properly. Remember to count bits from 0.

\$\endgroup\$
3
  • \$\begingroup\$ You also avoid sign shift problems by shifting right. Otherwise you must use an unsigned literal. eg 1u. \$\endgroup\$
    – Jeroen3
    Oct 10, 2018 at 7:58
  • \$\begingroup\$ @Jeroen3 I don't see how the sign is relevant considering that the masking is done afterwards. \$\endgroup\$ Oct 10, 2018 at 11:30
  • \$\begingroup\$ @HarrySvensson It should not be functionally relevant, but some compilers (or static code analysis) will warn you about it. \$\endgroup\$
    – Jeroen3
    Oct 10, 2018 at 12:08
2
\$\begingroup\$

One of the things to look out for is the amount of CPU cycles required for shifting. Some processor have a barrel-shifters thus shifting by 1 or by 3,4,.. N takes the same time.

Micro-controllers often can shift only 1 position per clock cycle. Thus >> 7 takes 7 clocks.

Therefore I often use:

new_pos = (old_pos & (1 << BIT_POSITION)) ? (1 << NEW_BIT_POSITION) : 0;

A second advantage is that your new bit position can be left or right of the old one. This code does not care about that whilst you otherwise have to think about shifting right or left.

Of course a small variant allows you to add bits to an existing variable:

new_pos |= (old_pos & (1 << BIT_POSITION)) ? (1 << NEW_BIT_POSITION) : 0;
\$\endgroup\$
7
  • 1
    \$\begingroup\$ Which MCU can shift only 1 position per cycle? \$\endgroup\$ Oct 10, 2018 at 11:46
  • \$\begingroup\$ @MarkoBuršič AVRtiny/mega and PIC12/16 are two I know of the top of my head. \$\endgroup\$
    – Jon
    Oct 10, 2018 at 12:04
  • \$\begingroup\$ Migrate to ARM and you'll have a much faster MCU, executing in one single cycle. \$\endgroup\$ Oct 10, 2018 at 12:17
  • 1
    \$\begingroup\$ @MarkoBuršič PIC still smokes ARM for extreme low power applications. Will hopefully change in the future, but for now many of us are stuck with memory banks and the W register. \$\endgroup\$
    – Jon
    Oct 10, 2018 at 12:57
  • 1
    \$\begingroup\$ @Jon If your PIC needs 8 cycles to perform this, while an ARM can do it in 1 cycle, your PIC needs 8 times more power to perform the calculation. You have to look at the total power consumption over time, not on lowest peak use. \$\endgroup\$
    – Lundin
    Oct 15, 2018 at 11:00
1
\$\begingroup\$

Update: One more question. I need to set a particular bit in a uint8 to a value X(not toggling the bit). eg: In 1100 0101, I need to set bit 2 to X, without modifying the other bits - to obtain 1100 0X01. I have been racking my brain, but I can't land on a straight forward solution.

To achieve this:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

#define BIT_POSITION 2
#define SET_BIT 1
#define CLR_BIT 0


uint8_t setOrClearBit(uint8_t variable, uint8_t bit_position, uint8_t setOrClear)
{
    if(setOrClear) {
        variable |= (1<<bit_position); 
    }
    else {
        variable &= ~(1<<bit_position);
    }
    return variable;
}

uint8_t test = 0b11000001;
int main(void)
{
     printf("%d\n", setOrClearBit(test, BIT_POSITION, SET_BIT));
    printf("%d\n", setOrClearBit(test, BIT_POSITION, CLR_BIT));

}

Or if no conditionals required:

uint8_t setOrClearBit(uint8_t variable, uint8_t bit_position, uint8_t setOrClear)
{
    variable = (variable & ~(1<<bit_position)) | (setOrClear<<bit_position);
    return variable; 
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.