Have you ever had to use bit shifting in real programming projects? Most (if not all) high level languages have shift operators in them, but when would you actually need to
I still write code for systems that do not have floating point support in hardware. In these systems you need bit-shifting for nearly all your arithmetic.
Also you need shifts to generate hashes. Polynomial arithmetic (CRC, Reed-Solomon Codes are the mainstream applications) or uses shifts as well.
However, shifts are just used because they are handy and express exactly what the writer intended. You can emulate all bit-shifts with multiplication if you want to, but that would be harder to write, less readable and sometimes slower.
The compilers detect cases where multiplication can be reduced to a shift.
Bit shifting doesn't solve high level programming problems, but just we sometimes have to solve lower level problems, and it's convenient to not have to write a separate library in C to do it. That's when it gets used most is my guess.
I have personally used it in writing an encoder for an EBCDIC character set converter.
yep. I have to write encryption algorithms before and that definitely uses them.
They are also useful when using integers etc for keeping track of statuses.
Another very common thing is to do a 4 bit shift when extracting the high nibble of a byte, i.e.
#define HIGH_NIBBLE(byte) (((byte) >> 4) & 0x0F)
#define LOW_NIBBLE(byte) ( (byte) & 0x0F)
Bit shifts are fast. They were implemented in CPU instruction sets long before division and modulus operations were. Many of us have used bit shifts for arithmetic that is simple on pencil and paper, but not available on our CPUs.
For example:
When I wrote in assembly language, my code was full of bit-shifting and masking.
Did it a fair amount in C, as well.
Haven't done it much in JavaScript or server languages.
Probably the best modern use is to step through a packed array of boolean values represented as ones and zeros. I used to always left shift and check for sign bit in assembly, but in higher level languages you compare against a value.
For example, if you have 8 bits, you check the top bit with "if (a>127) {...}". Then you left shift (or multiply by 2), do an "and" with 127 (or do a subtraction of 256 if the last bit was set), and do it again.