# Defining and using Bit Flags in C

#### misterT

##### Well-Known Member
There are many ways to access single bits in C. This first one is my favorite method.

First, lets define some macros to help manipulate single bits:
C:
/* Bit Operation macros */
#define sbi(b,n) ((b) |= (1<<(n)))          /* Set bit number n in byte b */
#define cbi(b,n) ((b) &= (~(1<<(n))))       /* Clear bit number n in byte b   */
#define fbi(b,n) ((b) ^= (1<<(n)))          /* Flip bit number n in byte b    */
#define rbi(b,n) ((b) & (1<<(n)))           /* Read bit number n in byte b    */

/* Examples */
volatile uint8_t flags;

sbi(flags,0); /* set bit 0 in 'flags' */
cbi(flags,3); /* clear bit 3 in 'flags' */

/* Test whether bit 0 is set */
if(rbi(flags,0)) { /*...*/ }
That allready looks pretty handy, but you still need to remember where each flag is located and what the purpose of the flag is.
With couple of more macros and defines we can hide this little detail from the user and make our code more readable, flexible and more safe.

C:
#define set_flag(combo)   sbi(combo)
#define clear_flag(combo) cbi(combo)

/* Define your flags in the format: (variable),(bit_number) */
#define FLAG_SRAM         (sram_flags),(0)
#define FLAG_REFRESH      (sram_flags),(1)
#define FLAG_REGISTER         (GPIOR0),(0)
#define FLAG_ERROR            (GPIOR0),(1)
#define FLAG_INTERRUPT        (GPIOR0),(3)

/* Now our code starts to look very readable, making comments almost useless and redundant */
volatile uint8_t sram_flags;

set_flag(FLAG_SRAM)     /* set sram flag */
clear_flag(FLAG_ERROR); /* clear error flag */

/* Test whether error flag is set */

/* You can make those if-statements even more readable by defining */
#define flag_is_set(combo)    rbi(combo)
#define flag_is_clear(combo)  (!rbi(combo))

if(flag_is_set(FLAG_SRAM)) { /*...*/ }
if(flag_is_clear(FLAG_SRAM)) { /*...*/ } /* That is almost like reading plain english. */
The above method gives you the freedom to locate individual flags where ever you want.. even in a general purpose register for efficient access.
It also lets you change the flag location without modifying every line of code where you access the bit.

One other method is to use structs and bitfields, but this is not as flexible as the previous method.
C:
/* Define structure with 8 one bit bitfields */
struct bits
{
uint8_t bit0:1;
uint8_t bit1:1;
uint8_t bit2:1;
uint8_t bit3:1;
uint8_t bit4:1;
uint8_t bit5:1;
uint8_t bit6:1;
uint8_t bit7:1;
};

/* Now, we could use this structure straight as a variable like this */
volatile struct bits flags;

flags.bit0 = 1; /* set bit 0 in 'flags' */
flags.bit3 = 0; /* clear bit 3 in 'flags' */

/* Test whether bit 0 is set */
if(flags.bit0) { /*...*/ }

/* Or, we could map the structure to some register or variable for extra flexibility and performanse */
#define flags_bit0  (((volatile struct bits*)&flags)->bit0)
#define flags_bit1  (((volatile struct bits*)&flags)->bit1)
#define flags_bit2  (((volatile struct bits*)&flags)->bit2)
#define flags_bit3  (((volatile struct bits*)&flags)->bit3)
#define flags_bit4  (((volatile struct bits*)&flags)->bit4)
#define flags_bit5  (((volatile struct bits*)&flags)->bit5)
#define flags_bit6  (((volatile struct bits*)&flags)->bit6)
#define flags_bit7  (((volatile struct bits*)(0x1E))->bit7) /* This bit is mapped in register (memory address 0x1E) for extra performance */

volatile uint8_t flags;

flags_bit0 = 1; /* set bit 0 in 'flags' */
flags_bit3 = 0; /* clear bit 3 in 'flags' */

/* Test whether bit 0 is set */
if(flags_bit0) { /*...*/ }
I tested these methods with 8 bit AVR (GCC) and all the methods produced exactly same results in simple test cases. Register variables of course were much more efficient than flags in sram.

Last edited:

#### NorthGuy

##### Well-Known Member
I think the traditional approach with masks is more flexible. You can set/clear/toggle several bits at a time.

If you wish you can define macros with bit numbers:

C:
#define BIT0 0x0001
#define BIT1 0x0002
#define BIT2 0x0004
Then you can operate several bits at a time:

C:
x ^= BIT0 | BIT2 | BIT11;
Compare to:

C:
fbi(x, 0);
fbi(x, 2);
fbi(x,11);
You can also store a combination of flags in a variable, for example:

C:
data_bits = BIT0 | BIT11 | some_additional_flags; // the variable now holds the set of flags

...

x |= data_bits; // and we can set all these flags
x &= ~data_bits; // or perhaps reset them late
Or, if you want it less cryptic:

C:
#define SET(x,b) x|=b
#define RESET(x,b) x&=~(b)
#define TOGGLE(x,b) x^=b

SET(x,data_bits);
TOGGLE(x,BIT2);
But, certainly, there are many ways to skin a cat.

#### misterT

##### Well-Known Member
True, good addition to the topic.

I was only considering situation where bits are used as flags.. that is: to flag out single event or condition. I assumed that only one bit at a time is modified. In that situation it is nice to name those flags and just use them. No need to know where they are actually located etc.. could be a variable in sram, could be a register.. All you need is the "name" of the flag. (and you can easily map a single bit anywhere you want)

When you change the state of one bit only the compiler is able to use the efficient SBI or CLI instruction. When you write many bits at a time then the compiler may not optimize properly.. don't know if any compiler is smart enough to use two SBI instructions when you say something like: x |= 0x03

Edit: Actually, if compiler uses two SBI instructions to do "x |= 0x03" it would be (horribly) wrong.
If simultaneous update is not important, then setting those bits one at a time can be more efficient. It can also be less efficient.. haha.

Last edited:

#### misterT

##### Well-Known Member
I did some tests.. Setting multiple bits in SRAM variable and in register variable.

Code:
;/* SRAM variables */

;/* Setting 3 bits in sram at the same time */
;sram |= BIT0 | BIT1 | BIT2;
00000052  LDS R24,0x0100        Load direct from data space
00000054  ORI R24,0x07          Logical OR with immediate
00000055  STS 0x0100,R24        Store direct to data space

;/* Setting 3 bits in sram one at a time */
;set_flag(SRAM0);
00000057  LDS R24,0x0100        Load direct from data space
00000059  ORI R24,0x01          Logical OR with immediate
0000005A  STS 0x0100,R24        Store direct to data space
;set_flag(SRAM1);
0000005C  LDS R24,0x0100        Load direct from data space
0000005E  ORI R24,0x02          Logical OR with immediate
0000005F  STS 0x0100,R24        Store direct to data space
;set_flag(SRAM2);
00000061  LDS R24,0x0100        Load direct from data space
00000063  ORI R24,0x04          Logical OR with immediate
00000064  STS 0x0100,R24        Store direct to data space

;/* Register variables */

;/* Setting 3 bits in a register at the same time */
;GPIOR0 |= BIT0 | BIT1 | BIT2;
00000066  IN R24,0x1E         In from I/O location
00000067  ORI R24,0x07        Logical OR with immediate
00000068  OUT 0x1E,R24        Out to I/O location

;/* Setting 3 bits in a register one at a time */
;set_flag(REG0);
00000069  SBI 0x1E,0        Set bit in I/O register
;set_flag(REG1);
0000006A  SBI 0x1E,1        Set bit in I/O register
;set_flag(REG2);
0000006B  SBI 0x1E,2        Set bit in I/O register
This is SRAM flag vs. register flag when you have those efficient instructions (SBI, CBI, SBIC, SBIS) available.
Code:
    ;if(read_flag(REG0)) { clear_flag(REG0); }
00000052  SBIC 0x1E,0        Skip if bit in I/O register cleared
00000053  CBI 0x1E,0         Clear bit in I/O register

00000052  LDS R24,0x0100        Load direct from data space
00000054  SBRS R24,0            Skip if bit in register set
00000055  RJMP PC+0x0006        Relative jump
00000056  LDS R24,0x0100        Load direct from data space
00000058  ANDI R24,0xFE         Logical AND with immediate
00000059  STS 0x0100,R24        Store direct to data space

Last edited:

#### NorthGuy

##### Well-Known Member
With SRAM, it could've optimized three flag sets into one. I actually expected the code to be exact the same in both cases. I guess it depends on the compiler.

With GPIO, the possibility to optimize depends on the number of bits being set. If you set 1 or 2 bits, then it's better to use SBI. If you need to set 3 bits, it's three instructions either way, but SBI is still preferable because it doesn't use any working register. If you need to set 4 or more bits, ORI is better because it's only 3 instructions. I wonder if it would figure out to use two SBI instructions instead of ORI if you would ask it to set exactly 2 bits, e.g. "GPIOR0 |= 3"?

#### misterT

##### Well-Known Member
With SRAM, it could've optimized three flag sets into one. I actually expected the code to be exact the same in both cases. I guess it depends on the compiler.
In AVR the SBI etc. instructions are only available to memory locations 0xFF and below. So it does depend on the hardware and the compiler.

If you mean that it could combine the individual flag sets into one ORI.. I think that would be wrong to optimize like that. What if you intend to set the flags one after the other.. not all at once.

#### NorthGuy

##### Well-Known Member
If you mean that it could combine the individual flag sets into one ORI.. I think that would be wrong to optimize like that. What if you intend to set the flags one after the other.. not all at once.
Yes, you're right. With I/O it could be important to set flags in some order. For example, in PICs you often must set all bits in a module register before you set the "enable" bit, otherwise it gets enabled with old bits.

However, with RAM locations these two should be equivalent:

C:
x |= 7;
C:
x |= 1;
x |= 2;
x |= 4;

#### misterT

##### Well-Known Member
However, with RAM locations these two should be equivalent:

C:
x |= 7;
C:
x |= 1;
x |= 2;
x |= 4;
I think it is wrong for a compiler to make assumptions about the order you intend to do things. And those two examples above are different.

Should this:
C:
x |= 1;
x |= 2;
x |= 4;
Compile to exactly same asm instructions as this:
C:
x |= 1;
x |= 4;
x |= 2;
I think not. No matter where x is located.

Last edited:

#### NorthGuy

##### Well-Known Member
I think it is wrong for a compiler to make assumptions about the order you intend to do things.
Lot of optimization is done that way. This only matters if if these variables may be accessed from other threads or ISRs. If that's a problem, then these variables can be defined as volatile, which tells the compiler to avoid this sort of optimization.

For example:

C:
for (i = 0; i < n; i++) {
x[i] = a + b;
}
This could be optimized as:

C:
temp = a + b;
for (i = 0; i < n; i++) {
x[i] = temp;
}
This makes the code faster without any side effects. Of course, if "a" or "b" is volatile (e.g. an SFR, or a variable modifiable from an ISR), such optimization cannot be done. But otherwise, you won't even notice uless you look at the disassembly.

Moreover, it's perfectly perfect for the compiler to cast away "i" completely and use some fast way to fill the array with a fixed value.

#### NorthGuy

##### Well-Known Member
Here's an example with GNU C

C:
#include <stdio.h>
int x = 0;

void p1() {
x |= 7;
}

void p2() {
x |= 1;
x |= 2;
x |= 4;
}

void main() {

p1();
p2();

printf("%d",x);

}
Code:
#cc b.c -o b -O2 --save-temps
Code:
    .file    "b.c"
.text
.p2align 4,,15
.globl p1
.type    p1, @function
p1:
pushl    %ebp
movl    %esp, %ebp
orl    7, x popl %ebp ret .size p1, .-p1 .p2align 4,,15 .globl p2 .type p2, @function p2: pushl %ebp movl %esp, %ebp orl7, x
popl    %ebp
ret
.size    p2, .-p2
.section    .rodata
.LC0:
.string    "%d"
.text
.p2align 4,,15
.globl main
.type    main, @function
main:
leal    4(%esp), %ecx
andl    $-16, %esp pushl -4(%ecx) pushl %ebp movl %esp, %ebp pushl %ecx subl$12, %esp
movl    x, %eax
orl    $7, %eax movl %eax, x pushl %eax pushl$.LC0
call    printf
movl    -4(%ebp), %ecx
leave
leal    -4(%ecx), %esp
ret
.size    main, .-main
.globl x
.bss
.align 4
.type    x, @object
.size    x, 4
x:
.zero    4
.ident    "GCC: (GNU) 4.5.0"
.section    .note.GNU-stack,"",@progbits
As you can see, they both came out the same.

#### misterT

##### Well-Known Member
Lot of optimization is done that way. This only matters if if these variables may be accessed from other threads or ISRs. If that's a problem, then these variables can be defined as volatile, which tells the compiler to avoid this sort of optimization.
Of course. I assume that the code is used in time critical embedded application.. This is electronics forum. If I code for PC I do not bother with bit flags..

Last edited:

#### Ian Rogers

##### User Extraordinaire
Forum Supporter
If I code for PC I do not bother with bit flags..
I wish to add... Pics have separate access registers...

There only several locations where bit access is allowed on the humble pic... Each range is different. The only way to "bit access" a normal ram location, is via high level code...

If I create a union to access bit flags, it has to be created with a bit access register! Bit manipulation is a different thing.

RB0 = 1; is bit access..

char x;
if(x & 0x1)... is bit manipulation...