Bit Hacking with Go

Vladimir Vivien
Feb 2, 2017 · 8 min read
 &   bitwise AND
| bitwise OR
^ bitwise XOR
&^ AND NOT
<< left shift
>> right shift

The & Operator

Given operands a, b
AND(a, b) = 1; only if a = b = 1
else = 0
func main() {
var x uint8 = 0xAC // x = 10101100
x = x & 0xF0 // x = 10100000
}
func main() {
var x uint8 = 0xAC // x = 10101100
x &= 0xF0 // x = 10100000
}
import (
“fmt”
“math/rand”
)
func main() {
for x := 0; x < 100; x++ {
num := rand.Int()
if num&1 == 1 {
fmt.Printf(“%d is odd\n”, num)
} else {
fmt.Printf(“%d is even\n”, num)
}
}
}
// Run this program in the Go Playground.

The | Operator

Given operands a, b
OR(a, b) = 1; when a = 1 or b = 1
else = 0
func main() {
var a uint8 = 0
a |= 196
fmt.Printf(“%b”, a)
}
// prints 11000100
^^ ^
// Run on Playground
func main() {
var a uint8 = 0
a |= 196
a |= 3
fmt.Printf(“%b”, a)
}
// prints 11000111// Run on Playground

Bits as Configuration

const (
UPPER = 1 // upper case
LOWER = 2 // lower case
CAP = 4 // capitalizes
REV = 8 // reverses
)
func main() {
fmt.Println(procstr(“HELLO PEOPLE!”, LOWER|REV|CAP))
}
func procstr(str string, conf byte) string {
// reverse string
rev := func(s string) string {
runes := []rune(s)
n := len(runes)
for i := 0; i < n/2; i++ {
runes[i], runes[n-1-i] = runes[n-1-i], runes[i]
}
return string(runes)
}

// query config bits
if (conf & UPPER) != 0 {
str = strings.ToUpper(str)
}
if (conf & LOWER) != 0 {
str = strings.ToLower(str)
}
if (conf & CAP) != 0 {
str = strings.Title(str)
}
if (conf & REV) != 0 {
str = rev(str)
}
return str
}
// Run on Go Playground

The ^ Operator

Given operands a, b
XOR(a, b) = 1; only if a != b
else = 0
func main() {
var a uint16 = 0xCEFF
a ^= 0xFF00 // same a = a ^ 0xFF00
}
// a = 0xCEFF (11001110 11111111)
// a ^=0xFF00 (00110001 11111111)
func main() {
a, b := -12, 25
fmt.Println(“a and b have same sign?“, (a ^ b) >= 0)
}
// Run on the Go Playground

^ as Bitwise Complement (NOT)

func main() {
var a byte = 0x0F
fmt.Printf(“%08b\n”, a)
fmt.Printf(“%08b\n”, ^a)
}

// prints
00001111 // var a
11110000 // ^a
// Run on the Playground

The &^ Operator

Given operands a, b
AND_NOT(a, b) = AND(a, NOT(b))
AND_NOT(a, 1) = 0; clears a
AND_NOT(a, 0) = a;
func main() {
var a byte = 0xAB
fmt.Printf("%08b\n", a)
a &^= 0x0F
fmt.Printf("%08b\n", a)
}
// prints:
10101011
10100000
// Run on the Playground

The << and >> Operators

Given integer operands a and n,
a << n; shifts all bits in a to the left n times
a >> n; shifts all bits in a to the right n times
func main() {
var a int8 = 3
fmt.Printf(“%08b\n”, a)
fmt.Printf(“%08b\n”, a<<1)
fmt.Printf(“%08b\n”, a<<2)
fmt.Printf(“%08b\n”, a<<3)
}
// prints:
00000011
00000110
00001100
00011000
func main() {
var a uint8 = 120
fmt.Printf(“%08b\n”, a)
fmt.Printf(“%08b\n”, a>>1)
fmt.Printf(“%08b\n”, a>>2)
}
// prints:
01111000
00111100
00011110
func main() {
a := 200
fmt.Printf(“%d\n”, a>>1)
}
// prints:
100
// Run on Playground
func main() {
a := 12
fmt.Printf(“%d\n”, a<<2)
}
// prints:
48
// Run on Playground
func main() {
var a int8 = 8
fmt.Printf(“%08b\n”, a)
a = a | (1<<2)
fmt.Printf(“%08b\n”, a)
}
// prints:
00001000
00001100
// run on Playground
func main() {
var a int8 = 12
if a&(1<<2) != 0 {
fmt.Println(“take action”)
}
}
// prints:
take action
// run on Playground
func main() {
var a int8 = 13
fmt.Printf(“%04b\n”, a)
a = a &^ (1 << 2)
fmt.Printf(“%04b\n”, a)
}
// prints:
1101
1001
// run on Playground

A Note on Arithmetic Shifts

Conclusion

Learning the Go Programming Language

Short and insightful posts for newcomers learning the Go programming language

Vladimir Vivien

Written by

Software Eng • Go Programming • Kubernetes • Author http://golang.fyi

Learning the Go Programming Language

Short and insightful posts for newcomers learning the Go programming language