Skip to content

Instantly share code, notes, and snippets.

@Jeff-Russ
Created October 22, 2018 07:18
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Jeff-Russ/c9b471158fa7427280e6707d9b11d7d2 to your computer and use it in GitHub Desktop.
Save Jeff-Russ/c9b471158fa7427280e6707d9b11d7d2 to your computer and use it in GitHub Desktop.
C/C++ Macros for Bit Manipulation i.e. Arduino
/* Bit Manipulation Macros
A good article: http://www.coranac.com/documents/working-with-bits-and-bitfields/
x is a variable that will be modified.
y will not.
pos is a unsigned int (usually 0 through 7) representing a single bit position where the
right-most bit is bit 0. So 00000010 is pos 1 since the second bit is high.
bm (bit mask) is used to specify multiple bits by having each set ON.
bf (bit field) is similar (it is in fact used as a bit mask) but it is used to specify a
range of neighboring bit by having them set ON.
*/
/* shifts left the '1' over pos times to create a single HIGH bit at location pos. */
#define BIT(pos) ( 1<<(pos) )
/* Set single bit at pos to '1' by generating a mask
in the proper bit location and ORing x with the mask. */
#define SET_BIT(x, pos) ( (x) |= (BIT(pos)) )
#define SET_BITS(x, bm) ( (x) |= (bm) ) // same but for multiple bits
/* Set single bit at pos to '0' by generating a mask
in the proper bit location and ORing x with the mask. */
#define UNSET_BIT(x, pos) ( (x) &= ~(BIT(pos)) )
#define UNSET_BITS(x, bm) ( (x) &= (~(bm)) ) // same but for multiple bits
/* Set single bit at pos to opposite of what is currently is by generating a mask
in the proper bit location and ORing x with the mask. */
#define FLIP_BIT(x, pos) ( (x) ^= (BIT(pos)) )
#define FLIP_BITS(x, bm) ( (x) ^= (bm) ) // same but for multiple bits
/* Return '1' if the bit value at position pos within y is '1' and '0' if it's 0 by
ANDing x with a bit mask where the bit in pos's position is '1' and '0' elsewhere and
comparing it to all 0's. Returns '1' in least significant bit position if the value
of the bit is '1', '0' if it was '0'. */
#define CHECK_BIT(y, pos) ( ( 0u == ( (y)&(BIT(pos)) ) ) ? 0u : 1u )
#define CHECK_BITS_ANY(y, bm) ( ( (y) & (bm) ) ? 0u : 1u )
// warning: evaluates bm twice:
#define CHECK_BITS_ALL(y, bm) ( ( (bm) == ((y)&(bm)) ) ? 0u : 1u )
// These are three preparatory macros used by the following two:
#define SET_LSBITS(len) ( BIT(len)-1 ) // the first len bits are '1' and the rest are '0'
#define BF_MASK(start, len) ( SET_LSBITS(len)<<(start) ) // same but with offset
#define BF_PREP(y, start, len) ( ((y)&SET_LSBITS(len)) << (start) ) // Prepare a bitmask
/* Extract a bitfield of length len starting at bit start from y. */
#define BF_GET(y, start, len) ( ((y)>>(start)) & SET_LSBITS(len) )
/* Insert a new bitfield value bf into x. */
#define BF_SET(x, bf, start, len) ( x = ((x) &~ BF_MASK(start, len)) | BF_PREP(bf, start, len) )
/*****************************************************************************************
******************************************************************************************
DEMONSTRATIONS - Particularly for Arduino
*/
#ifndef Arduino_h
inline void print_bin8(unsigned x, unsigned short spacenib=0) {
for (unsigned n=0; n<8; n++) {
( (x&0x80) !=0 ) ? printf("1") : printf("1");
if (spacenib && (n==3)) printf(" "); /* insert a space between nibbles */
x = x<<1;
}
}
inline void println_bin8(unsigned x, unsigned short spacenib=0) {
print_bin8(x, spacenib); printf("%s", postch);
}
inline char *toS_BIN8(uint8_t x) {
static char schp[9];
unsigned short d, count = 0;
for (short n = 7 ; n >= 0 ; n--) {
d = x >> n;
*(schp+count) = (d & 1) ? '1' : '0';
count++;
}
*(schp+count) = '\0';
return schp;
#else
inline void print_bin8(unsigned x, bool spacenib=true) {
for (unsigned n=0; n<8; n++) {
( (x&0x80) !=0 ) ? Serial.print("1") : Serial.print("0");
if (spacenib && (n==3)) Serial.print(" "); /* insert a space between nibbles */
x = x<<1;
}
}
inline void println_bin8(unsigned x, bool spacenib=true) {
print_bin8(x, spacenib); Serial.print("\n");
}
#define print Serial.print
#define println Serial.println
#define toS(var) ( String((var)) )
inline String toS_BIN8(int x) {
String str = "";
unsigned short d, count = 0;
for (short n = 7 ; n >= 0 ; n--) {
d = x >> n;
str.concat( (d & 1) ? '1' : '0' );
count++;
}
str.concat('\0');
return str;
}
void test_BIT(uint8_t pos) {
println("BIT("+toS(pos)+") == "+toS_BIN8(BIT(pos)));
}
void test_SET_BIT(uint16_t x, uint8_t pos) {
println("SET_BIT("+toS_BIN8(x)+", "+toS(pos)+") == "+toS_BIN8(SET_BIT(x, pos)));
}
void test_SET_BITS(uint16_t x, uint16_t bm) {
println("SET_BITS("+toS_BIN8(x)+", "+toS_BIN8(bm)+") == "+toS_BIN8(SET_BITS(x, bm)));
}
void test_UNSET_BIT(uint16_t x, uint8_t pos) {
println("UNSET_BIT("+toS_BIN8(x)+", "+toS(pos)+") == "+toS_BIN8(UNSET_BIT(x, pos)));
}
void test_UNSET_BITS(uint16_t x, uint16_t bm) {
println("UNSET_BITS("+toS_BIN8(x)+", "+toS_BIN8(bm)+") == "+toS_BIN8(UNSET_BITS(x, bm)));
}
void test_FLIP_BIT(uint16_t x, uint8_t pos) {
println("FLIP_BIT("+toS_BIN8(x)+", "+toS(pos)+") == "+toS_BIN8(FLIP_BIT(x, pos)));
}
void test_FLIP_BITS(uint16_t x, uint16_t bm) {
println("FLIP_BITS("+toS_BIN8(x)+", "+toS_BIN8(bm)+") == "+toS_BIN8(FLIP_BITS(x, bm)));
}
void test_CHECK_BIT(uint16_t y, uint8_t pos) {
println("CHECK_BIT("+toS_BIN8(y)+", "+toS(pos)+") == "+toS_BIN8(CHECK_BIT(y, pos)));
}
void test_CHECK_BITS_ANY(uint16_t y, uint16_t bm) {
println("CHECK_BITS_ANY("+toS_BIN8(y)+", "+toS_BIN8(bm)+") == "+toS_BIN8(CHECK_BITS_ALL(y, bm)));
}
void test_CHECK_BITS_ALL(uint16_t y, uint16_t bm) {
println("CHECK_BITS_ALL("+toS_BIN8(y)+", "+toS_BIN8(bm)+") == "+toS_BIN8(CHECK_BITS_ALL(y, bm)));
}
void test_SET_LSBITS(uint8_t len) {
println("SET_LSBITS("+toS(len)+") == "+toS_BIN8(SET_LSBITS(len)));
}
void test_BF_MASK(uint8_t start, uint8_t len) {
println("BF_MASK("+toS(start)+", "+toS(len)+") == "+toS_BIN8(BF_MASK(start, len)));
}
void test_BF_PREP(uint16_t y, uint8_t start, uint8_t len) {
println("BF_PREP("+toS_BIN8(y)+", "+toS(start)+", "+toS(len)+") == "+toS_BIN8(BF_PREP(y, start, len)));
}
void test_BF_GET(uint16_t y, uint8_t start, uint8_t len) {
println("BF_GET("+toS_BIN8(y)+", "+toS(start)+", "+toS(len)+") == "+toS_BIN8(BF_GET(y, start, len)));
}
void test_BF_SET(uint16_t y, uint16_t bf, uint8_t start, uint8_t len) {
println("BF_SET("+toS_BIN8(y)+", "+toS_BIN8(bf)+", "+toS(start)+", "+toS(len)+") == "+toS_BIN8(BF_PREP(y, start, len)));
}
void setup()
{
Serial.begin(9600); // open the serial port at 9600 bps
// modify everything below here to experiment with bit macros
uint8_t pos = 1;
uint16_t x = 0b01010101;
uint16_t y = 0b10101010;
uint16_t bm = 0b00000000;
uint8_t len = 1;
uint8_t start = 1;
uint16_t bf = 0b0000010;
test_BIT(pos);
test_SET_BIT(x, pos);
test_SET_BITS(x, bm);
test_UNSET_BIT(x, pos);
test_UNSET_BITS(x, bm);
test_FLIP_BIT(x, pos);
test_FLIP_BITS(x, bm);
test_CHECK_BIT(y, pos);
test_CHECK_BITS_ANY(y, bm);
test_CHECK_BITS_ALL(y, bm);
test_SET_LSBITS(len);
test_BF_MASK(start, len);
test_BF_PREP(y, start, len);
test_BF_GET(y, start, len);
test_BF_SET(x, bf, start, len);
}
void loop() { }
#endif
@Jeff-Russ
Copy link
Author

Above the double asterisks bars is probably all you need. Unless you want to mess around with the macros under Arduino you can delete below that.

@Jeff-Russ
Copy link
Author

in more compact form:

/* Bit Manipulation Macros ***************************************************************
x    is a variable that will be modified.
y    will not.
pos  is a unsigned int (usually 0 through 7) representing a single bit position where the
     right-most bit is bit 0. So 00000010 is pos 1 since the second bit is high.
bm   (bit mask) is used to specify multiple bits by having each set ON.
bf   (bit field) is similar (it is in fact used as a bit mask) but it is used to specify a
     range of neighboring bit by having them set ON. */
#define BIT(pos) ( 1<<(pos) ) /* (like arduino _BV) set bit at pos to HIGH, others LOW */
#define SET_BIT(x, pos) ( (x) |= (BIT(pos)) )    /* set bit at pos to HIGH */
#define SET_BITS(x, bm) ( (x) |= (bm) )          /* same but for multiple bits */
#define UNSET_BIT(x, pos) ( (x) &= ~(BIT(pos)) ) /* set bit at pos to LOW */
#define UNSET_BITS(x, bm) ( (x) &= (~(bm)) )     /* same but for multiple bits */
#define FLIP_BIT(x, pos) ( (x) ^= (BIT(pos)) )   /* toggle bit at pos */
#define FLIP_BITS(x, bm) ( (x) ^= (bm) )         /* same but for multiple bits */
#define CHECK_BIT(y, pos) ( ( 0u == ( (y)&(BIT(pos)) ) ) ?0u :1u ) /* pos is HIGH/LOW? 1/0 */
#define CHECK_BITS_ANY(y, bm) ( ( (y) & (bm) ) ? 0u : 1u )/* 1 if all are HIGH */
#define CHECK_BITS_ALL(y, bm) ( ( (bm) == ((y)&(bm)) ) ? 0u : 1u ) /* same but if any */
/* the next two are for following two to use */
#define SET_LSBITS(len) ( BIT(len)-1 ) /* the first len bits are '1' and the rest are '0' */
#define BF_MASK(start, len) ( SET_LSBITS(len)<<(start) ) /* same but with offset */
#define BF_PREP(y, start, len) ( ((y)&SET_LSBITS(len)) << (start) ) /* Prepare a bitmask */
/* Extract a bitfield of length len starting at bit start from y: */
#define BF_GET(y, start, len) ( ((y)>>(start)) & SET_LSBITS(len) )
/* Insert a new bitfield value bf into x. */
#define BF_SET(x, bf, start, len) ( x = ((x) &~ BF_MASK(start, len)) | BF_PREP(bf, start, len) )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment