Bit Operations

```Bit Operations
• C is well suited to system programming because it
contains operators that can manipulate data at the bit
level
– Example: The Internet requires that bits be
manipulated to create addresses for subnets and
supernets
• Two categories of bit operators
– Logical bitwise operators
– Shift bitwise operators
Bit operations
A bit can have one of two values: 0 or 1. The C language
provides four operators that can be used to perform bitwise
operations on the individual bits of any integer data type
(signed or unsigned char, short, int, and long):
Bitwise and
Bitwise inclusive or
Bitwise exclusive or
One’s complement
&
|
^
~
& and | are binary operators
Require integral operands: integer or char
Bit by bit comparison between the two operands
Bit operations
and: The and (&) operator takes two operands. A bit in the
result is 1 if and only if both of the corresponding bits in the
operands are 1. For example:
x = 01100010
y = 10111010
x&y = 00100010
or: The or (|) operator also takes two operands. A bit in the
result is 1 if and only if either one or both of the
corresponding bits in the operands are 1. For example
x = 01100010
y = 10111010
x|y = 11111010
Bit operations
Differences between && and & operators:
Logical and (&&)
• Result of && is always 0 or 1
• The evaluation of an expression that uses &&
terminates if the first operand is false (zero)
Bitwise and (&)
• The result of & can be any number
• Expressions with the & operator are always
completely evaluated
Bit operations
Differences between || and | operators:
Logical or (||)
• Result of || is always 0 or 1
• The evaluation of an expression that uses ||
terminates if the first operand is true (1)
Bitwise or (|)
• The result of | can be any number
• Expressions with the | operator are always
completely evaluated
Bit operations
xor: The xor (^) operator takes two operands. A bit in the
result is 1 if and only if exactly one of the corresponding
bits in the operand is 1. For example
x = 01100010
y = 10111010
x^y = 11011000
Bit operations
• The complement operator is unary in that it requires a
single operand. The other three are binary and require
two operands.
complement: The operator complement (~) converts 0
bits to 1 and 1 bits to 0. For example,
x = 01100010
~x = 10011101
Bit operations
In addition to the boolean operations, C also provides
binary operators that can be used to shift all the bits of any
integer type to the left or the right.
The left shift operator (<<) is used to shift bits to the left.
The left operand is the integer value to be shifted, and the
right is the number of bits to shift it. For example,
x = 01100010
x<<4 = 00100000
n
A left shift of n bits is a very efficient way to multiply by 2
Bit operations
The right shift operator (>> )is used to shift bits to the right.
The operands are identical to those used in left shift.
The left operand is the bit string and the right operand is the
number of bits to shift.
Bit operations
The right shift operator (>> ) (cont’d)
However, an important difference is that the value of new
bits shifted in from the left is machine dependent.
Nevertheless, it is commonly the case that the new bit will
be 0 unless (1) the left operand is a signed integer and (2)
the high order bit was originally a 1. In this case the integer
value represents a negative number and the shifting in of 1
bits keeps it negative.
An example of the right shift:
x = 01100010
x>>4 = 00000110
n
A right shift of n bits is a very efficient way to divide by 2
Bitwise Use
• Used as flags: 0 is off, and 1 is on
• Use bit mask to set and test flags
• Mask – variable or constant, usually stored in a byte of
short integer, that contains a bit configuration used to
control the setting or testing of bits in a bitwise operation
Example of a bit mask in a short integer
1000 0000 1000 0001
Bit 15
Bit 0
Creating Masks
• One-bit mask examples:
– mask5 = 1 << 5
00000001 << 5 -> 00100000
– mask1 = 1 << 1
00000001 << 1 ->
00000010
– mask = mask1 | mask5
00000010 | 00100000 -> 00100010
Masking
Masking is a commonly used technique in processing
individual bits of an integer word. In this technique, bits in the
mask corresponding to bits of interest in the target word are
set to 1 and the others are set to 0.
The mask and the target word are then and’ed. Here are
some examples of masking (assume x is an integer):
if ((x & 0x1) == 1)
printf("x is odd\n"); /* Simple test for even/odd */
right2 = x & 0x3;
/* Extract right 2 bit values */
bit10 = (x>>10) & 0x1; /* Extract bit 10 value
righthalf = x & 0xffff;
*/
/* Extract right half of integer*/
Creating Masks
Suppose we want to turn off the 5 leftmost bits of a number
stored in an 8-bit byte. The mask should start with the five
zero bits to turn off the first 5 bits and then contain 3 one bits
to leave the last three unchanged.
Operator &
number xxxxxxxx
mask 00000111
------------result 00000xxx
Creating Masks
Example: We know that in ASCII code, uppercase and
lowercase letters differ by only 1 bit in bit 5. The lowercase
letters have a 1 in bit 5, the uppercase letters have a 0. It is
easy to change a lowercase letter by using an appropriate
mask to turn off bit 5.
char 'a'
mask
result 'A'
01100001
11011111
------------01000001
Masks
• The bitwise and operator (&) is used to force masked bits
in a variable to 0.
• The bitwise inclusive or operator (|) is used to force
masked bits in a variable to 1.
• The bitwise exclusive or operator (^) is used to force
masked bits in a data item to change.
Exercise: Find the mask that when used with the & operator
sets the second and fourth bits of an 8-bit integer to zero.
Exercise: Find the mask that when used with the | operator
sets the second and fourth bits of an 8-bit number to 1.
Nibble
The term "nibble" is used to describe 4 bits. In particular, a
byte (8-bits) is composed of 2 nibbles. A 4-byte (32 bit)
integer is composed of 8 nibbles. So we might view an
integer as follows:
nibble 0 nibble 1
nibble 2 nibble 3
nibble 4 nibble 5 nibble 6 nibble 7
The decimal value "294610" in binary (base 2) is equal to
1011100000102. In memory the value would be stored as
illustrated by the following 8 nibbles:
0000 0000 0000 0000 0000 1011 1000 0010
Note that nibble 7 has the value 00102, and nibble 5 has the
value 10112.
Conversions
In addition to decimal (base 10) and binary (base 2),
hexadecimal (base 16) is commonly used to represent values
in our field. A single digit in hexadecimal can be represented
in 4 bits (a nibble). The binary and hexadecimal values of the
decimal values 0-15 are shown in the following table. Also
included are the octal (base 8) values:
Hexadecimal
Note that the letters "A-F" are used to represent the 6
additional "digits" in the hexadecimal system. Keep in mind
that 15 in decimal, and 1111 in binary and F in hexadecimal
are ALL the same value -- they are just different ways of
representing the same value (we could extend this to roman
numerals, i.e. "XV" -- this is just another representation of the
same number).
In C we can represent a hexadecimal value by prefixing it with
a "0x". For example, "x=0xf;" sets "x" to the decimal value 15
(or the binary value 1111). The statement "x=0xff" would set x
to the binary value "11111111", which is 255 in decimal.
Hexadecimal
When we do masking, we often find that using the
hexadecimal notation is useful (since it corresponds more
directly to bits and nibbles).
We can ask C to print a value in hexadecimal (as opposed to
decimal) by using the "%X" format item, for example if y=12,
then
printf("y=%d (%X)\n", y, y);
would print the value of y in both decimal and hexadecimal,
e.g.:
y=12 (C)
```