(Adapted from The Bit Math Tutorial in The Arduino Playground)
There are two bit shift operators in C++: the left shift operator << and the right shift operator >>. These operators cause the bits in the left operand to be shifted left or right by the number of positions specified by the right operand.
More information on bitwise math can be obtained in the Wikipedia article on bitwise operations, especially the section on shifts in C, C++, and Java.
Here are some examples of bit shifting, with the binary representation of the number in comments:
int a = 5; // binary: 101
int b = a << 3; // binary: 101000, or 40 in decimal
int c = b >> 3; // binary: 101, or back to 5 like we started with
When you left shift a value x by y bits (x << y), the leftmost y bits in x are lost, literally shifted out of existence. We’ll do this example with char values (which are integers in the range 0-255, and take up 8 bits of memory):
char a = 5; // binary (all 8 bits): 00000101
char b = a << 7; // binary: 10000000 - the first 1 in 101 was discarded
If you are certain that none of the ones in a value are being shifted into oblivion, a simple way to think of the left-shift operator is that it multiplies the left operand by 2 raised to the right operand power (in math notation, x << y equals x * 2y, as long as none of the bits of x get shifted out). For example, to generate powers of 2, the following expressions can be employed:
1 << 0 == 1
1 << 1 == 2
1 << 2 == 4
1 << 3 == 8
...
1 << 8 == 256
1 << 9 == 512
1 << 10 == 1024
...
When you shift x right by y bits (x >> y), and the highest bit in x is a 1, the behavior depends on the exact data type of x. If x is of type int, the highest bit is special, and determines whether x is negative or not; the details are too complicated to explain here, but they are thoroughly explained in the Wikipedia article on two’s complement arithmetic, which the system most computers use to store integers. In that case, the sign bit is copied into lower bits, for esoteric historical reasons:
int x = -16; // binary (all 32 bits): 11111111111111111111111111110000
int y = x >> 3; // binary: 11111111111111111111111111111110
This behavior, called “sign extension”, is often not what you want. You probably wish zeros to be shifted in from the left. It turns out that the right shift rules are different for unsigned int values, so you can use a type cast to suppress ones being copied from the left:
int x = -16; // binary: 11111111111111111111111111110000
int y = (unsigned int)x >> 3; // binary: 00011111111111111111111111111110
If you are careful to avoid sign extension, you can use the right-shift operator, >>, as a way to divide by powers of 2. For example:
int x = 1000;
int y = x >> 3; // integer division of 1000 by 8, causing y = 125.
Since it’s part of the C++ language, bit shifting on the Maple is compatible with the Arduino; however, you should keep in mind that the Maple has bigger integer types (as in, more bits) than the Arduino.
Since the STM32 is a 32-bit processor, the int type takes up 32 bits instead of 16, like on Arduino’s 16-bit microcontroller. This means that you can shift left, like x << y, with bigger values of y on the Maple before ones in x start to get shifted out.
To calculate the number of bits of an integer type on the Maple, multiply its size in bytes (see this table for these) by 8, since there are 8 bits in 1 byte. For example, a short takes up 2 bytes of memory, or 2 * 8 = 16 bits.
License and Attribution
Portions of this page were adapted from the Arduino Reference Documentation, which is released under a Creative Commons Attribution-ShareAlike 3.0 License.