------------------------------------------------ "Bit Operators in Practice" ------------------------------------------------ C/O :: arp of DynamicHell Development Team ------------------------------------------------ http://dynamichell.org | irc.dynamichell.org ------------------------------------------------ Note ==== It must be noted that this tutorial is aimed at users with a basic understanding of binary. Introduction ============ As a C/C++ programmer you will have become familiar with various means of manipulating data. However, it is highly likely that the smallest unit you have so far dealt with is a byte which size is defined by the constant CHAR_BIT. It must be noted that CHAR_BIT is always guaranteed to be greater-than or equal to 8 bits in size; on various architectures and operating systems this size does vary. Though for all our purposes we will assume a CHAR_BIT to be 8 bits in size. And with all examples 8-bit unsigned integers are used. You may have wondered whether or not it is possible to manipulate the individual bits in an integer, long, char or short. The answer is yes. There are many uses for bitwise operators, but perhaps the most common is the use of a single integer or long to store various flags. Rather than store each value in a seperate variable, each option can be assigned a bit in a single integer. Much more efficient! C and C++ provide the programmer with six means of manipulating individual bits within an integer, long, char or short. These are appropriately named operators. The six operators for manipulating bits follow: Operator Description -------- --------------------- & Bitwise AND operator | Bitwise OR operator ^ Bitwise XOR operator ~ Bitwise NOT operators << Left-shift operator >> Right-shift operator Each of these operators serves a different function to the programmer. Note: The short, long, int and char data types that you are manipulating are called operands. This tutorial aims to introduce bit operators, operands and their usage. The Bitwise AND Operator ======================== The bitwise & operator works by comparing each bit in operand x with operand y. If both bits are 1 (on) then 1 is placed in the same bit in the result. However, if one or two of the bits are 1 (on) then 0 is placed in the same bit in the result. Example: z = 7 & 3 z = 0000 0111 & 0000 0011 0000 0111 & 0000 0011 --------- 0000 0011 Therefore 3 = 7 & 3. The & operator is commonly used to turn bits off in the result which are on in x but not on in y. As the third bits from the left show in the above example. The & operator is also often used to see whether the bits in x, match the bits set in y. For example to test whether bits 1 and 2 (from the left) are set in operand x you would use the following statement: if(x & 3) /* if(x & 0000 0000 0000 0011) */ puts("Bits one and two are set."); else puts("Bits one and two are not set."); The Bitwise OR Operator ======================= The bitwise | operator works by comparing each bit in operand x with operand y. If either bit is 1 (on) then 1 is placed in the result. The same also applies if both bits are 1 (on). The | operator is commonly used to set bits that are on in operand y but not in operand x. For example, to set bits 2 and 3 (from the left) on in x you would use the following assignment. z = 9 | 6 z = 0000 1001 | 0000 0110 0000 1001 | 0000 0110 --------- 0000 1111 Therefore, 15 = 9 | 6. The Bitwise XOR Operator ======================== The bitwise ^ operator works by comparing each bit in operand x with operand y. If either bit, but not both, is 1 (on) then 1 is placed in the result. Example: z = 7 ^ 3 z = 0000 0111 ^ 0000 0011 0000 0111 ^ 0000 0011 --------- 0000 0100 Therefore, 4 = 7 ^ 3. The Bitwise NOT Operator ======================== The bitwise ~ operator works with only one operand. Each bit in the operand is reversed. So that 1 (on) becomes 0 (off), and 0 becomes 1. Example: z = ~(7) z = ~(0000 0111) ~ 0000 0111 --------- 1111 1000 Therefore, 248 = ~7. Of course we are assuming the use of two 8-bit integers. The Left-Shift Operator ======================= The << operator works by shifting the bits of an operand so many bits to the left. To shift x by y bits to the left you would use the statement x << y. Example: Where : x = 12; Statement: x << 3; 0000 1100 << 3 --------- 0110 0000 Therefore, if x = 12 and x << 3 then x = 96. The Right-Shift Operator ======================== The >> operator works by shifting the bits of an operand so many bits to the right. To shift x by y bits to the right you would use the statement x >> y. Example: Where : x = 96; Statement: x >> 3; 0110 0000 >> 3 --------- 0000 1100 Therefore, if x = 96 and x >> 3 then x = 12. Example Code ============ The following includes example code which can be built to aid the understanding of bitwise and bitshift operators. /* bitwise_and.c */ #include #include int main(void) { unsigned int x = 7, y=3, z=0; puts("\nThe bitwise AND operator (&) places 1 in the result if "); puts("both operands are 1. 0 is placed in the result if either"); puts("operands are 0.\n"); puts("x = 0111, y = 0011, z = 0000"); puts("----------------------------"); puts("With z = x & y (z = 0111 & 0011)"); puts("z should equal 0011"); puts("----------------------------"); z = x & y; printf("z = %u\n\n",z); return EXIT_SUCCESS; } /* End of bitwise_and.c */ /* bitwise_or.c */ #include #include int main(void) { unsigned int x = 9, y=6, z=0; puts("\nThe bitwise OR operator (|) places 1 in the result if "); puts("either operand, including both, is 1.\n"); puts("x = 1001, y = 0110, z = 0000"); puts("----------------------------"); puts("With z = x | y (z = 1001 | 0110)"); puts("z should equal 1111"); puts("----------------------------"); z = x | y; printf("z = %u\n\n",z); return EXIT_SUCCESS; } /* End of bitwise_or.c */ /* bitwise_xor.c */ #include #include int main(void) { unsigned int x = 7, y=3, z=0; puts("\nThe bitwise XOR operator (^) places 1 in the result if "); puts("either operands are 1, but not both.\n"); puts("x = 0111, y = 0011, z = 0000"); puts("----------------------------"); puts("With z = x ^ y (z = 0111 ^ 0011)"); puts("z should equal 0100"); puts("----------------------------"); z = x ^ y; printf("z = %u\n\n",z); return EXIT_SUCCESS; } */ End of bitwise_xor.c */ /* biwise_not.c */ #include #include int main(void) { unsigned short x = 9; /* 16-bit unsigned integer on 32-bit integer systems.*/ puts("\nThe bitwise NOT operator (~) reverses each bit in the operand. "); puts("Thus, only one operand is used.\n"); puts("x = 0000000000001001 = 9"); puts("------------------------------------"); puts("With x = ~x (x = ~0000000000001001)"); puts(" ----------------"); puts(" = 1111111111110110"); puts("------------------------------------"); x = ~x; printf("Inverted x = %u and inverted again\n",x); x = ~x; printf("~x = %u\n\n",x); return EXIT_SUCCESS; } /* End of bitwise_not.c */ /* bitshift.c */ #include #include int main(void) { unsigned int x = 12; unsigned int y = 3; puts("Here x is 12 and y is 3"); printf("x << y is %u\n",x << y); printf("Here x is %u and y is %u\n",x,y); printf("x >> y is %u\n",x >> y); return EXIT_SUCCESS; } */ End of bitshift.c */ Copright (c) 2005. Alastair Poole. Verbatim copying and distribution of this entire article are permitted worldwide, without royalty, in any medium, provided this notice, and the copyright notice, are preserved.