Why Binary?

i
 ,_,
(O,O)
(   )
-"-"-

Integers

i
print(0b101101)  # (1 * 32) + (1 * 8) + (1 * 4) + 1
i
45

Hexadecimal

i
print(0x2D)  # (2 * 16) + 13
i
45

Negative Numbers

Two's Complement

Table 1: 3-bit integer values using two's complement.
Base 10 Base 2
3 011
2 010
1 001
0 000
-1 111
-2 110
-3 101
-4 100

Two's Complement

Bitwise Operations

Bitwise Operations

Table 2: Bitwise operations.
Expression Bitwise Result (bits) Result (decimal)
12 & 6 1100 & 0110 0100 4
12 | 6 1100 | 0110 1110 14
12 ^ 6 1100 ^ 0110 1010 10
~ 6 ~ 0110 1001 9
12 << 2 1100 << 2 110000 48
12 >> 2 1100 >> 2 0011 3

This Is Not Arithmetic

Storing Numbers

Boxed values
Figure 1: Using boxed values to store metadata.

Storing Arrays

Boxed arrays
Figure 2: Low-level and high-level array storage.

Packing and Unpacking

The struct Module

i
import struct

fmt = "ii"  # two 32-bit integers
x = 31
y = 65

binary = struct.pack(fmt, x, y)
print("binary representation:", repr(binary))

normal = struct.unpack(fmt, binary)
print("back to normal:", normal)
i
binary representation: b'\x1f\x00\x00\x00A\x00\x00\x00'
back to normal: (31, 65)

Hexadecimal Again

Packing With Counts

i
from struct import pack

print(pack("3i", 1, 2, 3))
print(pack("5s", bytes("hello", "utf-8")))
print(pack("5s", bytes("a longer string", "utf-8")))
i
b'\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00'
b'hello'
b'a lon'

Dynamic Formats

i
text = "hello"
print(f"{len(text)}s")
i
5s

Variable-Length Packing

i
def pack_string(as_string):
    as_bytes = bytes(as_string, "utf-8")
    header = pack("i", len(as_bytes))
    format = f"{len(as_bytes)}s"
    body = pack(format, as_bytes)
    return header + body

Variable-Length Packing

i
if __name__ == "__main__":
    result = pack_string("hello!")
    print(repr(result))
i
b'\x06\x00\x00\x00hello!'

Unpacking

i
def unpack_string(buffer):
   header, body = buffer[:4], buffer[4:]
   length = unpack("i", header)[0]
   format = f"{length}s"
   result = unpack(format, body)[0]
   return str(result, "utf-8")

buffer = pack_string("hello!")
result = unpack_string(buffer)
print(result)
i
hello!

Bytes and Text

Unicode

Unicode

Characters as Bytes

i
result = pack_string("こんにちは!")
print(repr(result))
i
b'\x10\x00\x00\x00\xe3\x81\x93\xe3\x82\x93\xe3\x81\xab\xe3\x81\xa1\x \
e3\x81\xaf!'

Binary Mode

Summary

Concept map for binary data
Figure 3: Concept map.