Everything in a computer is binary. An 8 bit char has 8 bits. Bitwise operators operate on those bits. So a char with value 253 is represented in memory as 11111101. Bitwise operator >> would shift all those 1s to the right, resulting in 01111110. Bitwise & runs the AND operation between two values at a bit-level. Same for |, XOR, etc.
That's clear enough, but I've never been able to wrap my head around why anyone would want to muck about with that. If I was working on the OS kernel or drivers or network implementations maybe? But even then if one wanted to do math with numbers wouldn't they do it with int and let the compiler optimise?
Depends on what you are doing. I personally have not had to do it in a few years. But typically for me it is if I am trying to move data between architectures (big vs little) and the native libs do not have the proper byte swaping things. Some of the older archs had some seriously odd ways of filling in bits to make a word. In some rare cases to save some bytes somewhere. Basically stuff them into some other field. For example I have 2 4 bit value range values and stuff them into 1 8 bit number. That takes up half the space. Also another use not seen much anymore was pixel bashing on a monitor. You had to know which bit a dataplane sat in so it would render correctly. These days it is usually 4 bytes, and even then only 3 are usually used.
These days you do not see bit packed fields as much but if you want to pop them out sometimes shifting and masking is more handy. Other times it gets in the way. Just depends on what you are doing. Also as storage and memory has increased the need for bitpacking things has decreased radically. But if you are doing something super critical it may be worth it just so your data fits into a cacheline and the extra instructions are worth not going out to the main store memory. The difference between 2MB total space to do something and 32GB is pretty immense so packing was borderline a necessity a few years ago. Now not so much.
Win32 OLE/COM error codes were a spot where masking and shifting was needed if you wanted to decode what was going wrong. If I remember correctly they did it that way so they could return the error code in 1 CPU register. But at a cost of code complexity.
If you do any automotive CAN bus work it is a veritable rabbit hole of playing with bits.
> But typically for me it is if I am trying to move data between architectures (big vs little) and the native libs do not have the proper byte swaping things.
Hm... Do any processors have native instructions for that? Like, swap "AA BB CC DD" into "DD CC BB AA", or perhaps "CC DD AA BB"? Maybe moving stuff from big- to little-endian or vice versa is too niche for that to be worthwile to implement in silicon (or microcode).
Anyway, speaking of endianness, ObPetPeeve: US date formatting -- fricking middle-endian! (And now, looking for that pithy quote about middle-endianness I can't find, I note that according to https://en.wikipedia.org/wiki/Endianness some machines actually were middle-endian. Sheesh...)
It's super common for embedded devices, and kernel development. Yeah compilers can mostly figure it out, but if you're really looking at the bits of a value, like in the example, you should operate on them bitwise, it's more clear, and definitely leaves no room for the compiler to leave it in an inefficient state.
Yeah, I'm a little embarrassed to say I'd have used an array do what's in the example. I wouldn't have done all the unnecessary string conversions, but if I have a sequence of 64 things and I want the first 22 things that's a slice operation in my head, not a bit-shift, even if the things are bits.
A great use of bitwise operators I came up with recently was to define a unique key with two sides(source and destination) in a single int. Just allocate one bit of the int to defining which side is represented and you have partitioned the space; everything after that is an exercise in masking and bit-flipping to determine matches.
Compare with the "sidecar a bool" approach that tends to come to mind to solve this task without bitwise operations; now you have to define a whole structure for it. It works, but it ain't elegant.
Hope that helps.
Here come the well actuallys.