Bits, Bools, and Bit-fields

Programs often need objects that can act as a flag to indicate a 1 or 0 value, or a true or false state. There are several objects suitable for this task when you are using the MPLAB® XC Compilers, and these objects are explained in the following sections and summarised in the table at the end of this article.

Boolean objects

The _Bool type is a standard C type available when using the C99 or later C standard. Use the <stdbool.h> header file when using this type, which allows you to use macros like true and false for the values held by these objects.

_Bool objects can be made any size by the compiler (provided they are able to store 0 and 1) however, many implementations allocate an entire byte for such objects, as is the case with all MPLAB XC compilers. You can determine the size of a _Bool object or type by using the sizeof() operator.

When any scalar value is converted to type _Bool, the result is 0 (false) if the value compares equal to 0; otherwise, the result is 1 (true). This conversion is markedly different from the usual integer conversion rules employed by the C language.

#include <stdbool.h>

_Bool buttonDown;
unsigned int state = 0x42;

buttonDown = state;     // buttonDown assigned 'true' (1)
if(buttonDown == true)
  processRequest();

As with ordinary objects, you can take the address of _Bool objects and define pointers to such objects. Structure members can be defined as type _Bool, if required; however, you might consider using bit-fields in this situation, discussed in the next section.

_Bool * bp;
struct {
  _Bool button1;
  _Bool button2;
} buttonState;

bp = &buttonDown;
buttonState.button1 = *bp;

Bit-fields

Bit-fields are special objects that can be used only as members inside structures. They are available in all implementations of standard C (including C90), although some aspects of their operation are implementation-defined.

The number of bits allocated to a bit-field is specified when it is defined. To create a flag, allocate just a single bit to a bit-field by following the bit-field's name with :1. Bit-fields are packed into bytes, and as their placement in those bytes is strictly specified by the order in which they are defined in the structure, structures containing bit-fields are commonly used with unions to allow access to an entire byte (or bytes) and the bits which make up that byte (or bytes).

union {
  unsigned char byte;
  // a structure with 8 single bit bit-field objects, overlapping the union member "byte"
  struct {
    unsigned b0:1;
    unsigned b1:1;
    unsigned b2:1;
    unsigned b3:1;
    unsigned b4:1;
    unsigned b5:1;
    unsigned b6:1;
    unsigned b7:1;
  };
} byte_u;

if(byte_u.byte = 0x10)  // access the entire byte
    byte_u.b4 = 1;      // access just one bit in that byte

Bit-fields are recognized as having an integer type. Conversions from scaler values wider than the bit-field are usually performed by truncating the higher-order bits in the value that are not represented in the bit-field destination. You cannot take the address of bit-field objects, nor define pointers to such objects, but you can perform these actions against the entire structure in which the bit-fields reside.

Bit Objects

The __bit type is a non-standard type implemented only by MPLAB XC8 when building for PIC devices, and hence projects using this type may not be portable to other projects or compilers. There are some restrictions on when objects of type __bit can be used, for example, they cannot be auto objects, but they can be qualified static, allowing them to be defined locally within a function.

__bit powerOn;

int func(void) {
    static __bit flameOn;
    // ...
}

These objects are always one bit in size, and you cannot specify a __bit object or type as the argument to the sizeof() operator. The XC8 compiler will pack 8 of these objects into one byte and access them using bit-orientated instructions, where possible.

The __bit type is an integer type (the signedness of single-bit objects does not make sense) so conversions from wider scaler values to __bit are performed by truncating all but the least significant bit in the value, potentially producing a different result to that obtained when assigning the same value to a _Bool.

__bit buttonDown;
unsigned int state = 0x42;

buttonDown = state;     // buttonDown assigned 0 (false)
if(buttonDown == 1)
  processRequest();

__bit objects are always represented by bit addresses (as opposed to conventional byte addresses), and bit addresses are shown for __bit objects and sections in list and map files. It is for this reason that you cannot take the address of __bit objects, nor can you define pointers to such objects. Structure members cannot be an object of type __bit.

Summary

The information in the above sections has been summarised in this table to help you select the best C type for your application. Check your favorite C language text or your compiler's user's guide for more information.

Type Portability Size Value Indirect
access?
sizeof(type)? Structure
member?
_Bool C99 or later often 1 byte boolean yes yes yes
bit-field Standard C 1 or more bits,
as specified
integer no no always
__bit XC8 only 1 bit integer no no no
© 2024 Microchip Technology, Inc.
Notice: ARM and Cortex are the registered trademarks of ARM Limited in the EU and other countries.
Information contained on this site regarding device applications and the like is provided only for your convenience and may be superseded by updates. It is your responsibility to ensure that your application meets with your specifications. MICROCHIP MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND WHETHER EXPRESS OR IMPLIED, WRITTEN OR ORAL, STATUTORY OR OTHERWISE, RELATED TO THE INFORMATION, INCLUDING BUT NOT LIMITED TO ITS CONDITION, QUALITY, PERFORMANCE, MERCHANTABILITY OR FITNESS FOR PURPOSE. Microchip disclaims all liability arising from this information and its use. Use of Microchip devices in life support and/or safety applications is entirely at the buyer's risk, and the buyer agrees to defend, indemnify and hold harmless Microchip from any and all damages, claims, suits, or expenses resulting from such use. No licenses are conveyed, implicitly or otherwise, under any Microchip intellectual property rights.