Working with Bits and Bit Fields in C and Objective-C

We’ll cover two bit related topics in this post: getting/setting bits directly within an integer and working with bit fields in a C structure. Both have their place, it’s more about the context in which you need to use them.

The first example will be getting/setting of specific bits using an integer value along with a pre-defined set of bits we want to access. From there we will look at creating a structure that has named bit fields, making access (and code readability) much easier.

Set Bits, Get Bits, Toggle Bits and Clear Bits

Let’s begin by defining a series of bits to access, followed by setting, getting, clearing and checking bits:

#define BIT_ONE   1
#define BIT_TWO   2
#define BIT_THREE 4
#define BIT_FOUR  8
 
int flag = 0;
 
// Set bits
flag |= BIT_ONE | BIT_THREE;
NSLog(@"Bits: %@", [self intToBinaryString:flag]);
 
// Clear bits
flag &= ~(BIT_ONE | BIT_THREE);
NSLog(@"Bits: %@", [self intToBinaryString:flag]);
 
// Toggle bits
flag ^= (BIT_ONE | BIT_THREE);
NSLog(@"Bits: %@", [self intToBinaryString:flag]);
 
// Check bit
if (flag & BIT_THREE)
  NSLog(@"Bit set");
else
  NSLog(@"Bit not set");

The output looks as follows:

2014-01-20 13:51:41.908 Sandbox[23386:70b] Bits: 00000101
2014-01-20 13:51:42.927 Sandbox[23386:70b] Bits: 00000000
2014-01-20 13:51:45.113 Sandbox[23386:70b] Bits: 00000101
2014-01-20 13:51:53.194 Sandbox[23386:70b] Bit set

Bit Fields using Structures

Let’s look at another example, this time using a C structure, which allows for an easy means to give names to the various bits we are after:

1
2
3
4
5
6
struct
{
  unsigned preLoaded: 1;
  unsigned saveState: 1;
  unsigned saveLoginName: 1;
} statusFlags;

I’ve defined three bit fields, all which will be saved within an unsigned integer. Accessing the bits is as easy as this:

1
2
3
4
5
6
7
// Setting bits
statusFlags.preLoaded = 1;
statusFlags.saveState = statusFlags.saveLoginName = 0;
 
// Get bits
if (statusFlags.saveLoginName == 0)
  ... do something here...

Using the sizeof() function, let’s compare the size of an integer to the size of the structure we created:

1
2
3
4
5
6
7
8
9
10
11
12
13
// Setting bits
statusFlags.preLoaded = 1;
statusFlags.saveState = 0;
statusFlags.saveLoginName = 1;
 
// Get bits
if (statusFlags.saveLoginName == 1)
  NSLog(@"saveLoginName bit is on.");
else
  NSLog(@"saveLoginName bit is off.");  
 
NSLog(@"Sizeof int: %ld", sizeof(int));
NSLog(@"Sizeof statusFlags: %ld", sizeof(statusFlags));

The output looks as follows, which verifies that the bit fields as defined above are all maintained within a single unsigned integer.

Bits and Bit fields

So we now know that we have up to 32 bit flags (4 bytes, 8 bits per byte) that we can use with this structure. Let’s create a new structure that looks as follows:

1
2
3
4
5
6
7
8
struct
{
  unsigned preLoaded: 1;
  unsigned saveState: 1;
  unsigned saveLoginName: 1;
  unsigned buffer: 28;
  unsigned savePassword: 1;
} statusFlagsExtended;

In this structure, ‘buffer’ is nothing more than a means for us to soak up 28 bits such that we can add one more bit on the end. Let’s take a look at the sizeof this structure with the code below:

1
2
3
4
5
6
7
8
9
10
11
12
13
// Setting bits
statusFlags.preLoaded = 1;
statusFlags.saveState = statusFlags.saveLoginName = 0;
 
// Get bits
if (statusFlags.saveLoginName == 0)
  NSLog(@"saveLoginName bit is on.");
else
  NSLog(@"saveLoginName bit is off.");  
 
NSLog(@"Sizeof int: %d", sizeof(int)); 
NSLog(@"Sizeof statusFlags: %d", sizeof(statusFlags));
NSLog(@"Sizeof statusFlagsExtended: %d", sizeof(statusFlagsExtended));

As expected, the structure ‘statusFlagsExtended’ is also stored as an integer.

Bits and Bitfields

Bit flags and bit fields are both handy. I encourage you to give them a go when you need to manage a series of on/off values.

Additional Reading

IBM has a decent overview of working with bit fields in their Mac OS X compilers documentation. The docs go back a few years, but it is a good read if you would like a few more examples on bit fields.

  1. Very nice article!
    This is a very clean and compact approach to a type of data structure I seem to find myself needing time and time again. Anxious to give it a go today!

  2. Thanks, good write-up!

    I know that bit fields are often used in enumerations. Is there a pattern we should use with NS_ENUM(), or do standard enumeration rules apply?

    • Good question. I don’t have a specific answer, however, I’ve read a little about NS_OPTION, have you looked into that macro?

    • Jeremy, as John already mentioned, take a look at NS_ENUM, it is exactly for this purpose.

  3. It is not quite correct to say that “bit fields are used as enumerations”. A bit field is used in structures, in order to define a portion of the structure with a width different than a standard type (usually shorter than a char). All enumerations must be of integral type. But a common technique, now standardized via the NS_OPTION macro, is to define enumeratied values as powers of two which can be OR’d together, allowing the storage of multiple flags in a single variable, accessible by masking.

    The defined BIT_ONE etc values above would have been better defined as enumerations, for example. A common practise allows defining powers of two using natural numbers:

    Enum {
    Bit_0 = 1 << 0,
    Bit_1 = 1 << 1,
    Bit_2 = 1 << 2
    };

    // set flags
    int flags = Bit_0 | Bit_1;

    // extract flags
    If (flags & Bit_0) {
    // do something
    }
    Else if (flags & Bit_1) {
    // do something else
    }

    Hopefully you recognize the bit shift operator, ehich produces valuse of 1, 2, and 4, but which the notation suggests are sequential.

    You do not need to use NS_OPTION to take advantage of bit flags, nor do you need to specify your enum type, but it is a good habit to get into.

    • Thanks for the thorough response. Regarding the comment “The defined BIT_ONE etc values above would have been better defined as enumerations” can you explain why the enum would be a better choice?

  4. It is a truism, of sorts, that C language features are always preferable to the preprocessor. You get type-checking, at least. In the case of enums, you also get switch statement support. Although that doesn’t apply for bit flags. If const works, don’t use #define.

  5. Some bit picking:

    There is a typo in the comment “// Toggle bit”, a missing “s”.
    It toggles two bits, not one. This can be seen in the output.

    The “// Check bits” output “Bits set” can be misleading.
    It gets printed, too, if bit one or bit three is set.
    Maybe “Bit(s) set” would be more precise.

Comments are closed.