Is there a way to address a single bit in C?
In plain C (without any extensions, whatever they may be), you can declare a variable as a bit field. It can save a lot of typing and is less error prone.
Here is an example program. It declares a bit field with an union with a regular type of the same size.
#include <stdio.h>
int main(int argc, char *argv[])
{
typedef struct
{
union
{
struct {
int bit0:1;
int bit1:1;
int bit2:1;
int bit3:1;
int bit4:1;
int bit5:1;
int bit6:1;
int bit7:1;
};
unsigned char byte;
};
} EigthBits;
EigthBits b;
b.byte = 0;
printf("Will be 0 ==> %d\n", b.byte);
b.bit4 = 1;
printf("Will be 16 ==> %d\n", b.byte);
}
Will print this output :
Will be 0 ==> 0 Will be 16 ==> 16
It is usefull to set values to individual bit on a control register, for example. You can set more bits (like int two_bits:2;
) to suit your needs.
This is not uncommon. For example, SDCC (Small Device C Compiler) is a popular compiler for MCS-51. You'll find the manual here. The most relevant section is 3.4.1, it describes the language extensions for MCS-51:
3.4.1.6 __bit
This is a data-type and a storage class specifier. When a variable is declared as a bit, it is allocated into the bit addressable memory of 8051, e.g.:
__bit test_bit;
Writing 1 to this variable generates the assembly code:
D2*00 setb _test_bit
The bit addressable memory consists of 128 bits which are located from 0x20 to 0x2f in data memory. Apart from this 8051 specific storage class most architectures support ANSI-C bitfields4. In accordance with ISO/IEC 9899 bits and bitfields without an explicit signed modifier are implemented as unsigned.
In C, you typically read one byte, and then mask the bit you want, but some processor-specific compilers pre-define registers or even individual bits for you. For example, the Keil Cx51 User's Guide defines bit and sfr data types.
You'd use the sfr
type like this:
sfr P0 = 0x80; // Port 0 is accessed at address 80h.
P0 = 0x20; // Write 20h to Port 0.
To use the byte-at-a-time method, you'd do something like this:
#define SFR (* (unsigned char *) 0x80) // Address of SFR is 0x80.
#define BIT0 0x01 // LSB of any byte
#define BIT1 0x02
#define BIT2 0x04
. . .
#define BIT7 0x80 // MSB of any byte
// Read BIT1 of SFR. sfrBit1 is 1 if BIT1 is set, 0 if not.
unsigned char sfrBit1 = SFR & BIT1 ? 1 : 0;
// Set BIT0 of SFR.
SFR |= BIT0;
// Clear BIT2 of SFR.
SFR &= ~BIT2;
For convenience, you can define utility macros to set and clear individual bits:
#define SET(reg, bit) reg |= (1 << bit) // Sets a bit in reg.
#define CLR(reg, bit) reg &= ~(1 << bit) // Clears a bit in reg.
SET(SFR, 1); // Set BIT1
CLR(SFR, 2); // Clear BIT2