I\'ve been studying C# and ran accross some familiar ground from my old work in C++. I never understood the reason for bitwise operators in a real application. I\'ve never u
Left and right shift operators (<< and >>) are often used in performance critical applications which do arithmetic operations and more specifically multiplications and divisions by powers of two.
For example suppose you had to calculate the mathematical expression 5*2^7
. A naive implementation would be:
int result = 5 * (int)Math.Pow(2, 7);
Using left shift operator you could write:
int result = 5 << 7;
The second expression will be orders of magnitude faster than the first and yet yielding the same result.
Except for combining flags, bit logic isn't necessarily something you need in your UI code, but it is still tremendously important. For example, I maintain a binary serialization library, that needs to deal with all sorts of complex bit-packing strategies (variant length base-128 integer encoding, for example). This is one of the implementations (actually, this is a slower/safer version - there are other variants for dealing with buffered data, but they are harder to follow):
public static bool TryDecodeUInt32(Stream source, out uint value)
{
if (source == null) throw new ArgumentNullException("source");
int b = source.ReadByte();
if (b < 0)
{
value = 0;
return false;
}
if ((b & 0x80) == 0)
{
// single-byte
value = (uint) b;
return true;
}
int shift = 7;
value = (uint)(b & 0x7F);
bool keepGoing;
int i = 0;
do
{
b = source.ReadByte();
if (b < 0) throw new EndOfStreamException();
i++;
keepGoing = (b & 0x80) != 0;
value |= ((uint)(b & 0x7F)) << shift;
shift += 7;
} while (keepGoing && i < 4);
if (keepGoing && i == 4)
{
throw new OverflowException();
}
return true;
}
We have:
This is real code, used in a real (and much used) protocol. In general, bit operations are used a lot in any kind of encoding layer.
It is also hugely important in graphics programming, for example. And lots of others.
There are also some micro-optimisations (maths intensive work etc) that can be done with bit operations.
Here's an everyday bitwise-op trick not many people have discovered:
When you have an enumerated type representing a bitfield, you need to define each enum entry as a distinct bit value, as in:
enum
{
Option1 = 1,
Option2 = 2,
Option3 = 4,
Option4 = 8,
Option5 = 16
};
but it's easy to forget that the next item in the sequence needs to be double the last number. Using bit shifting, it makes the sequence much easier to get right:
enum
{
Option1 = 1<<0,
Option2 = 1<<1,
Option3 = 1<<2,
Option4 = 1<<3,
Option5 = 1<<4
};
An example from COM programming:
An HRESULT is an error code consisting of a 32 bit integer. The high bit is a flag indicating whether the code represents success (0) or failure (1). The next 15 bits are an integer representing what sort of error it is -- an ole automation error or a win32 error or whatever. The lower 16 bits are the actual error code.
Being able to shift bits around is quite useful when you want to get information into or out of an HRESULT.
Now, you almost always want to abstract away the bit twiddling. It's much better to have a method (or in C, a macro) that tells you whether the HRESULT is failure, rather than actually twiddling out the bit with (hr & 0x80000000) != 0 right there in your source code. Let the compiler inline it.
There are lots of examples of low-level data structures where information is crammed into words and needs to be extracted with bitwise operations.
A typical use is manipulating bits that represent mutually exclusive 'flags'.
Example from MSDN: Enumeration Types
[Flags]
enum Days2
{
None = 0x0,
Sunday = 0x1,
Monday = 0x2,
Tuesday = 0x4,
Wednesday = 0x8,
Thursday = 0x10,
Friday = 0x20,
Saturday = 0x40
}
class MyClass
{
Days2 meetingDays = Days2.Tuesday | Days2.Thursday;
Days2 notWednesday = ~(Days2.Wednesday);
}
See also Stack Overflow question Most common C# bitwise operations.
There is a reason that, depending on the kind of person, can be important: cool-iness! ;)
Take this, an algorithm to calculate the absolute value of a number, without using any conditional branch instruction:
int abs(const int input) {
int temp = A >> 31;
return ( input ^ A ) - A;
}
A reason to avoid conditional branching is that it could stop your processor pre-fetching, waiting for the condition to be verified to know to which value the program counter should be set.
So, a part from the joke, there are very good technical reasons to do it.