Bitwise Logic and Binary
In the previous part of the C# Fundamentals tutorial I described the Boolean operators and their effect on Boolean values. The bitwise logic operators provide the same logical AND, OR and XOR functions for operation on each bit of integer values. This can be very useful for interrogating the value of individual bits in integers used as bit fields.
For developers who are new to interrogating individual bits in bit fields, consider the following example. Let us assume that we have a device connected to a serial port that indicates its status using one byte. This byte is comprised of eight binary digits, or bits, each providing some Boolean information. The following table describes the use of each bit. For clarity I have indicated the value that the byte would hold if it were a byte data type value with only that bit set.
Bit | Bit Value | Meaning (1) | Meaning (0) |
---|
7 | 128 | Ready | Off-Line |
6 | 64 | Connected | Not Connected |
5 | 32 | Carrier Present | Carrier Absent |
4 | 16 | Log Data | Do Not Log Data |
3 | 8 | Auto Answer Mode | Manual Answer Mode |
2 | 4 | Echo Commands | Do Not Echo Commands |
1 | 2 | Use 8 Data Bits | Use 7 Data Bits |
0 | 1 | Use Odd Parity | Use Even Parity |
Reading from our example device may yield a result of 187 or 10111011 in binary. Comparing this value to our table we can see that the device is ready, disconnected and has a carrier signal present. It is set to log data and answer automatically. It is not echoing commands and is using eight data bits and odd parity.
This is a lot of information to hold in or extract from a single byte of information. The following sections explain how to use the bitwise operators to read and process the bits.
Bitwise AND Operator
The bitwise AND operator is generally used to test the values of bits within a larger integer value. For our example device's output we may want to isolate the value of bit 5 to determine if a carrier signal is present. By using the AND operator with the value 32, all of the bits except bit 5 are cleared. In other words, the only possible set bit that can remain is bit 5. A simple diagram showing the binary and decimal representations will clarify this.
10111011 = 187
00100000 = 32
AND
00100000 = 32
Each binary digit pair is affected individually by the AND operation. Only bit 5 can possibly remain set in our result. This is the key to reading isolated bits using a bitwise AND. For a single bit, if the resultant value is zero then the bit was not set. If the result is non-zero, the tested bit must have been set.
The AND operation can also be used to clear bits in an integer value, ie. set some bits to zero. For example, to clear bit 5 from the configuration byte, indicating that the carrier signal is no lobger present, we can perform an AND operation with a value with bit 5 not set. Again, a binary representation will help to clarify this.
10111011 = 187
11011111 = 223
AND
10011011 = 155
To achieve a bitwise AND operation, we use the ampersand symbol (&). The following examples illustrate reading an isolated bit from an integer value.
int deviceConfiguration = 187; // 10111011
int carrierMask = 32; // 00100000
int connectedMask = 64; // 01000000
// Check the carrier
int carrier = deviceConfiguration & carrierMask; // Result = 32
// Check the connection status
int connected = deviceConfiguration & connectedMask; // Result = 0
Bitwise OR Operator
The bitwise OR operator is generally used to set bits within a larger integer value, ie. set some bits to one. For our example device, we may want to set bit 2 to indicate that we wish to echo commands. Let's look at the binary OR operation first.
10111011 = 187
00000100 = 4
OR
10111111 = 191
Each binary digit pair is affected individually by the OR operation. Wherever the second operand has a zero bit, the bit from the first operand is copied into the final result. However, if we set a one bit this ensures the matching resultant bit will be set to one.
To achieve a bitwise OR operation we use the bar character (|). The following example illustrates setting bits in an integer value.
int deviceConfiguration = 187; // 10111011
int echoMask = 4; // 00000100
// Set the carrier
int newConfiguration = deviceConfiguration | echoMask; // Result = 191
5 September 2006