Go's six bitwise operators, including &^, which clears bits, plus shifting, masks, flag sets built with iota, and the math/bits helpers.
1 See the bits inside an integer
Every integer is a row of bits. 12 is 1100, and 10 is 1010. A bitwise operator lines the two rows up and works down them a column at a time.
Print with %b to see the bits, and pad with a width so the rows line up.
a, b := 12, 10
fmt.Printf("%04b\n", a) // 1100
fmt.Printf("%04b\n", b) // 10102 Combine bits with AND, OR, and XOR
AND keeps a bit only where both sides have it. OR keeps it where either side does. XOR keeps it where exactly one side does.
a & b // 1000, the one column where both are 1
a | b // 1110, every column where either is 1
a ^ b // 0110, the columns where they disagree3 Flip every bit with NOT
Go writes NOT with the same symbol as XOR. One operand means NOT, two means XOR.
On a signed type the result looks odd until you remember the sign bit flips too, which is why ^i equals -i-1.
var u uint8 = 12
fmt.Printf("%08b", ^u) // 11110011, which is 243
i := 12
fmt.Println(^i) // -134 Clear bits with AND NOT
AND NOT keeps everything on the left except the bits the right has set. Elsewhere you would write a & ^b. In Go it is one operator.
a &^ b // 0100
// b is 1010, so bits 1 and 3 get cleared from a (1100),
// leaving only bit 2.5 Shift bits left and right
Left by one doubles the value, right by one halves it. Shifting past the width of the type leaves zero rather than wrapping.
12 << 1 // 24, bits 1100 become 11000
12 >> 2 // 3, bits 1100 become 0011
var x uint8 = 1
x << 9 // 0, shifted clean off the end6 Watch the sign on a right shift
This is the one place the signedness of your type changes the answer. Signed values keep their sign, so a negative stays negative.
var neg int8 = -8
neg >> 1 // -4, the sign bit is copied in
var pos uint8 = 248
pos >> 1 // 124, zeros are shifted in7 Build a flag set with iota
Shifting 1 by iota gives every constant its own bit, so one integer can carry a whole set of on-off options.
type Perm uint8
const (
Read Perm = 1 << iota // 001
Write // 010
Exec // 100
)
p := Read | Exec // 101
p |= Write // set: 111
p &^= Read // clear: 110
p ^= Exec // toggle: 010
if p&Write != 0 { // test
fmt.Println("writable")
}8 Pull out bits with a mask
AND against a mask keeps only the columns the mask has set. Testing the lowest bit is the usual even-or-odd check.
0xAB & 0x0F // 0xB, the low four bits
(0xAB >> 4) & 0x0F // 0xA, the high four
n & 1 == 0 // true when n is evenSix operators over one integer: & keeps, | adds, ^ differs or flips, &^ clears, and the two shifts move everything along.
Operator reference
| Verb | Prints | Example |
|---|---|---|
| & | AND. A bit survives only where both sides have it set. | 1100 & 1010 → 1000 |
| | | OR. A bit is set where either side has it set. | 1100 | 1010 → 1110 |
| ^ | XOR, between two values. A bit is set where the sides differ. | 1100 ^ 1010 → 0110 |
| ^x | NOT, with one operand. Flips every bit. | ^uint8(12) → 243 |
| &^ | AND NOT, or bit clear. Keeps the left bits, drops any the right has set. | 1100 &^ 1010 → 0100 |
| << | Shift left. Every bit moves up, zeros fill in behind. | 1100 << 1 → 11000 |
| >> | Shift right. Every bit moves down. | 1100 >> 2 → 0011 |
| Verb | Prints | Example |
|---|---|---|
| &= | Keep only the bits also set in the mask. | p &= mask → p = p & mask |
| |= | Turn a flag on. | p |= Write → p = p | Write |
| ^= | Toggle a flag. | p ^= Exec → p = p ^ Exec |
| &^= | Turn a flag off. | p &^= Read → p = p &^ Read |
| <<= | Shift left in place. | x <<= 3 → x = x << 3 |
| >>= | Shift right in place. | x >>= 3 → x = x >> 3 |
The math/bits package
Counting and rearranging bits by hand is fiddly, so the standard library does it. Each function comes in 8, 16, 32, and 64-bit versions, plus a plain uint one.
| Function | Description |
|---|---|
OnesCount8(x uint8) int bits.OnesCount8(12) // 2 | How many bits are set. |
LeadingZeros8(x uint8) int bits.LeadingZeros8(12) // 4 | Zero bits above the highest set bit. |
TrailingZeros8(x uint8) int bits.TrailingZeros8(12) // 2 | Zero bits below the lowest set bit. |
Len8(x uint8) int bits.Len8(12) // 4 | Bits needed to hold the value. |
Reverse8(x uint8) uint8 bits.Reverse8(12) // 48 | Reverses the bit order. |
RotateLeft8(x uint8, k int) uint8 bits.RotateLeft8(12, 1) // 24 | Rotates left, wrapping bits round the end. |
UintSize bits.UintSize // 64 | Bits in a uint on this platform, 32 or 64. |