To represent binary bit patterns in C, it is normal to use hexadecimal notation. The utility of hex is that a single hex digit exactly coincides with 4 binary digits, so with experience you can quickly convert between the 16 hex digits and the corresponding binary value in your head, and for longer integers it is simply a matter of converting each digit in turn - 4 bits at a time. Representing long integers in binary quickly becomes impractical.
So your table might be represented as:
uint8_t row[] = { 0xd3, // 11010011
0x53, // 01010011
0x80 // 10000000
} ;
Then you set/clear bits in the following manner:
row[2] |= mask ; // Set mask bits
row[0] &= mask ; // Clear mask bits
To create a mask specifying numbered bits without hard-coding the hex value you can use an expression such as:
uint8_t mask = 1<<7 | 1<<5 | 1<<0 ; // 10100001 mask bits 0, 5 & 7
Occasionally a "visual" binary representation is desirable - for character bitmaps for example, the character A is much easier to visualise when represented in binary:
00000000
00011000
00100100
01000010
01111110
01000010
01000010
00000000
It is possible to efficiently code such a table while maintaining the "visualisation" by exhaustively defining a macro for each binary value; e.g:
#define B_00000000 0x00
#define B_00000001 0x01
#define B_00000010 0x02
#define B_00000011 0x03
#define B_00000100 0x04
...
#define B_11111110 0xfe
#define B_11111111 0xff
Note to create the above macros, it is best perhaps to write a code generator - i.e. a program to generate the code, and put the macros in a header file.
Given such macros you can then represent your table as:
uint8_t row[] = { B_11010011
B_01010011
B_10000000
} ;
or the character bitmap for A thus:
uint8_t charA[] = { B_00000000,
B_00011000,
B_00100100,
B_01000010,
B_01111110,
B_01000010,
B_01000010,
B_00000000 } ;
In the case that the bits are received at run-time serially, then the corresponding uint8_t
can be built using sequential mask and shift:
uint8_t getByte()
{
uint8_t mask = 0x80 ;
uint8_y byte = 0 ;
while( mask != 0 )
{
uint8_t bit = getBit() ;
byte |= bit ? mask : 0 ;
mask >>= 1 ;
}
return byte ;
}
What the getBit()
function does is for you to define; it may read a file, or a string, or keyboard entry for example, but it must return either zero or non-zero or the binary digits 0
and 1
respectively. If the data is received LSB first then the mask starts from 0x01, and a <<
shift used instead.