Binary, Hexadecimal, and Octal: The Programmer's Field Guide
A practical guide to binary, hexadecimal, and octal number systems — bitwise operations, color codes, memory addresses, and fast conversion examples with real I/O.
Binary, Hexadecimal, and Octal: The Programmer's Field Guide
Every programmer eventually has to stare down a hex dump, decode a Unix permission bitmask, or extract an RGB channel from a CSS color. The underlying skill is the same in every case: reading numbers the way hardware does, not the way we learned in elementary school.
This guide covers the practical contexts where binary, hexadecimal, and octal appear in real code — with actual conversion examples, a rundown of bitwise operations, and pointers to tools that speed up the work.
Why Computers Don't Count in Decimal
Binary (base 2) maps directly onto digital electronics. A transistor is either saturated or cut off, so one bit holds exactly one of two values. Stack eight bits together and you get a byte: 256 possible states, from 00000000 to 11111111.
That mapping makes binary the native language of hardware, but it is impractical to read. A 32-bit value written in binary is 32 characters long. In hexadecimal (base 16), the same value collapses to 8 characters — a 4:1 compression ratio that makes register dumps, memory addresses, and packet headers legible. One hex digit represents exactly four bits (a nibble), so the conversion between binary and hex is purely mechanical: group bits in fours from the right, look up each group.
Octal (base 8) gives a 3:1 ratio — one octal digit covers three bits. It appeared naturally on older machines whose word sizes were multiples of three bits, and it survives today almost exclusively in Unix file permission notation.
Converting Between Bases: A Real I/O Example
Take the IPv4 address 192.168.1.100, stored in network byte order as a 32-bit unsigned integer. Here is the step-by-step conversion:
To binary:
192 → 11000000
168 → 10101000
1 → 00000001
100 → 01100100
full value: 11000000 10101000 00000001 01100100
To hexadecimal (group every 4 bits):
1100 0000 → C0
1010 1000 → A8
0000 0001 → 01
0110 0100 → 64
result: 0xC0A80164
Each byte becomes exactly two hex digits. Wireshark, tcpdump, and virtually every network tool display addresses this way. When I first started reading packet captures, translating 0xC0A80164 back to 192.168.1.100 in my head felt painstaking. After a few weeks of writing out the steps manually — and cross-checking with a Binary Calculator — the column-by-column pattern became automatic.
For less common conversions (base 36, BCD, or any unusual radix), the Base Converter handles arbitrary inputs without requiring you to memorize the division-and-remainder procedure.
Bitwise Operations: Where Binary Earns Its Keep
Bitwise operators act directly on the bit pattern of a value. Four show up constantly in real code: AND, OR, XOR, and NOT — plus the shift operators that move bits left or right.
AND for masking extracts specific bits by zeroing everything else. To pull the red channel out of a 24-bit RGB value:
color = 0xFF5733 binary: 11111111 01010111 00110011
red_mask = 0xFF0000 binary: 11111111 00000000 00000000
─────────
AND result = 0xFF0000 binary: 11111111 00000000 00000000
shift right 16 bits → 0xFF = 255
Red is 255, which matches the CSS value rgb(255, 87, 51) for that color.
OR for setting flags adds bits without disturbing the rest:
permissions = 0b100 (read-only)
write_bit = 0b010
─────────
result = 0b110 (read + write)
XOR for toggling flips only the bits present in the mask:
0b1100 XOR 0b0110 = 0b1010
Any bit set in both inputs becomes 0; any bit set in only one becomes 1. This makes XOR useful for checksums, simple encryption schemes, and the classic swap-without-a-temp-variable trick (a ^= b; b ^= a; a ^= b).
The Bitwise Calculator shows the A, B, and result values aligned column-by-column in binary, so you can see exactly which bits flipped. I use it to double-check flag masks before I embed them in production code — catching an off-by-one bit position costs five seconds there versus a full debugging session later.
Hex Color Codes and Memory Addresses
A CSS color like #FF5733 is three bytes of hexadecimal: one byte per channel, six characters total. The space covers 256³ = 16,777,216 distinct colors — every combination of 256 red values × 256 green values × 256 blue values. That matches the 24-bit color depth described in the sRGB standard (IEC 61966-2-1), which is what virtually every modern display targets.
Reading hex pairs directly is faster than converting to decimal in your head. #C0392B has a high red byte (0xC0 = 192, well above the 128 midpoint), a low-middle green byte (0x39 = 57), and near-zero blue (0x2B = 43). That is enough to recognize a dark red without opening a color picker or computing rgb(192, 57, 43) explicitly.
Memory addresses follow the same notation. A typical 64-bit pointer printed by a debugger looks like 0x00007ffe8b4a3210. The leading zeros show it sits in user space (kernel pointers on x86-64 typically start at or above 0xFFFF800000000000). Stack offsets in assembly listings, interrupt vector tables, hardware register maps — they are all expressed in hex because the nibble boundary makes bit-field boundaries obvious.
When a crash dump or core file lands in your lap, the ability to read hex addresses quickly is often the difference between finding the fault in minutes and spending an afternoon translating numbers.
Octal's Surviving Niche: Unix File Permissions
Unix file permissions still use octal because a nine-bit permission field (owner/group/world × read/write/execute) divides evenly into three three-bit groups, one octal digit each.
chmod 755 script.sh sets:
7 = 111 binary → rwx (owner: read + write + execute)
5 = 101 binary → r-x (group: read + execute)
5 = 101 binary → r-x (world: read + execute)
A common error is giving a shell script chmod 644, intending "readable by everyone, writable by owner." The binary breakdown reveals the problem immediately:
6 = 110 → rw- (owner: no execute)
4 = 100 → r-- (group: no execute)
4 = 100 → r-- (world: no execute)
None of the three groups has the execute bit set (the rightmost bit of each trio). The script will not run, and the error message — Permission denied — gives no hint that the issue is a single bit being zero. Writing 644 in binary first would have caught it instantly.
The permission 777 (111 111 111) means full access for every user on the system. Tutorials use it for convenience, but world-writable files let any local process overwrite or replace them — a significant risk on a shared server.
Fast Reference: Hex, Binary, and Decimal Anchors
You do not need to memorize the full conversion table. A handful of anchor points lets you interpolate the rest:
| Hex | Binary | Decimal | |-----|-----------|---------| | 00 | 00000000 | 0 | | 40 | 01000000 | 64 | | 7F | 01111111 | 127 | | 80 | 10000000 | 128 | | FF | 11111111 | 255 | | 0F | 00001111 | 15 | | F0 | 11110000 | 240 |
The midpoint byte (0x80 = 128) and the fully-set byte (0xFF = 255) appear constantly — in color channels, network masks (/24 = 0xFFFFFF00), protocol flags, and signed integer boundaries. Everything else is relative distance from those anchors.
For production work where mental math is not fast enough — a 64-bit hash, a packed network header, a binary protocol field — the right move is to use a calculator and get the value right on the first try.
Made by Toolora · Updated 2026-06-30