Octal as a byte-grouping notation
Octal is base 8, using digits 0 through 7 only. Like hex, it exists as a compact stand-in for binary rather than as a number system anyone naturally counts in, and like hex, the relationship is exact: because 8 is 2 cubed, each octal digit corresponds to precisely three binary digits. Where hex groups bits in fours, octal groups them in threes — 111 in binary is 7 in octal, the largest single digit, the same way 1111 is F in hex.
That 3-bit grouping is also octal's central limitation on modern hardware. Byte-oriented architectures work in multiples of 8 bits, and 8 doesn't divide evenly by 3 — representing one byte in octal takes anywhere from a partial to three full octal digits with an awkward remainder, unlike hex's clean two digits per byte. Octal made much more sense on machines with word sizes divisible by 3, such as the 12-bit and 36-bit words common on 1960s and 1970s minicomputers (the PDP-8 and PDP-11 families among them), where octal digits lined up with the hardware exactly the way hex does on today's 8/16/32/64-bit systems.
Converting between hex and octal
Unlike hex-to-binary, hex-to-octal isn't a direct digit-for-digit lookup, because 16 and 8 aren't powers of each other in a way that lines up per digit — 4 bits (one hex digit) and 3 bits (one octal digit) don't share a common short grouping. The practical method is to go through binary as an intermediate step: convert each hex digit to its 4-bit binary form, concatenate, then regroup the resulting bit string into 3-bit chunks from the right and convert each chunk to its octal digit (padding the leftmost chunk with zeros if it's short). For 0xFF: binary is 11111111, regrouped in threes from the right that's 011 111 111, which reads as octal 377. This converter performs that conversion through the underlying integer value directly rather than through manual bit regrouping, but the two methods always agree.
Where octal still appears today
Octal's most visible modern use is Unix and Linux file permission notation. A permission set likerwxr-xr-- is stored as three groups of three bits (read, write, execute for owner, group, and others), and three bits per group is exactly one octal digit — which is why chmod 755or chmod 644 use octal rather than hex or decimal. Some older network protocols, terminal escape sequences, and legacy file formats from the minicomputer era also specify values in octal, and a handful of programming languages retain octal literal syntax (0o17 in Python and JavaScript, or a bare leading zero like 017 in C) for backward compatibility with that history.
Octal in string escape sequences
Octal also survives inside string literals, independent of the numeric literal rules described above. C, and many languages descended from it, support octal escape sequences of the form \NNNinside a string — for example "\033" represents the ASCII escape character (decimal 27, hex 0x1B) written as octal 33. This convention predates the more familiar \xNN hex escape syntax and is still supported for compatibility even in languages that otherwise favor hex, including Python and C. Terminal control sequences and some older text protocols are still documented with octal escapes for this reason, which is one of the few places a developer encounters raw octal digits without going looking for them.
A worked example
Take the hex value 0x1A3, worth 419 in decimal. Converting via binary: 1 → 0001, A → 1010, 3 → 0011, giving the 12-bit string 000110100011. Regrouped into 3-bit chunks from the right: 000 110 100 011, which reads as octal digits 0, 6, 4, 3 — so 0x1A3 is 0643 in octal. Reversing the process, and dropping the leading zero, confirms the result: octal 643 is (6 × 8²) + (4 × 8¹) + (3 × 8⁰) = 384 + 32 + 3 = 419, matching the original decimal value.
A common source of bugs
Because a leading zero historically signaled an octal literal in C-derived languages, a value like017 written in source code with the intention of representing "seventeen, zero-padded" is actually interpreted as octal 17, which equals 15 in decimal — a mismatch that has caused real bugs in production code, particularly around date and time formatting where zero-padded numbers (like day 08or 09) show up constantly. Some languages, including modern JavaScript in strict mode, have since disallowed the ambiguous leading-zero-without-prefix form specifically to prevent this confusion, requiring an explicit 0o prefix for octal instead.
When reading unfamiliar code or configuration files, a bare number with a leading zero is worth a second look — it may be an octal literal rather than a decimal one padded for alignment, and the two can differ significantly once double-digit values are involved.