Advanced Bitwise Operations
Expanding on information covered in Bitflags, this document
further explores how other bitwise operators can be used. This document uses the
prefix 0b
to denote a binary number, to distinguish them from numbers in base
ten. For example, the base ten number 5 is 0b101
, and the base ten number
1,110 is 0b10001010110
.
Or Operator
The Or operator can be used merge bitflags, even if they contain the same flag.
var/a = 5 // 0b101
var/b = 6 // 0b110
var/c = a | b // 0b111 = 7
The Or operator can be used in conjunction with each other to reduce line count. This example from the previous bitflags document can be simplified.
var/player_abilities = WALK
player_abilities |= SING
player_abilities |= READ
Instead of assigning twice, we can simplify.
var/player_abilities = DANCE
player_abilities |= (SING|READ)
Note that these are now wrapped in parentheses, primarily to make them easier to read that they are a pair of OR’d bitflags.
And Operator
The And operator can be used to check if 2 variables contain the same bitflag.
var/a = 5 // 0b101
var/b = 6 // 0b110
var/c = a & b // 0b100 = 4
The only bit that stayed true was the bit that was in both inputs. This is different to the Or operator, where it only had to be in one input.
In the previous section, we turned a flag off using this example:
player_abilities &= ~SING
This done by using the & (And) operator and a negation of the bitflag. Negating this bitflag replace all the 1s with 0s and all the 0s with 1s.
#define DANCE (1 << 4) // 0b10000 = 16
to_chat(world, DANCE) // 0b10000 = 16, note that all the leading zeros have been hidden here.
to_chat(world, ~DANCE) // 0b111111111111111111101111 = 16777199
When the &= ~DANCE
operation is performed, it takes negated version, where the
flag is only zero and applies the and operation
var/player_abilities = (DANCE|SING|SWIM)
player_abilities &= ~DANCE // remove the dance flag
to_chat(world, player_abilities) // now just contains (SING | SWIM)
Exclusive Or Operator.
The exclusive or operator ^
acts as a “toggle”, and doesn’t require knowledge
of what is inside the flags, as seen in the example below.
var/player_abilities = (DANCE|SING|SWIM)
player_abilities ^= DANCE // remove the dance flag
to_chat(world, player_abilities) // (SING | SWIM)
player_abilities ^= DANCE // enable the dance flag
to_chat(world, player_abilities) // (DANCE | SING | SWIM)
When used between two variables, this can be used to check the differences between them.
var/a = 3 // 0b010
var/b = 5 // 0b101
var/c = a ^ b // 0b110 = 6
Bitwise Shift Right
Finally, in conjunction to <<
bitwise left shift, there is a bitwise right
shift, used with >>
. These shifts can also be used with numbers other than
one, as shown in the example below.
var/a = 5 // 0b101 = 5
var/b = (a<<3) // 0b101000 = 40
var/c = (b>>1) // 0b10100 = 20
However, using these shifts are not common outside of defining bitflags, bitwise right shift is barely used.
Not to be confused, these operators (<<
and >>
) are also used as “output”
and “input” operators for mobs, savefiles, etc. These are only rarely used,
users should be using helper procs like to_chat() instead.