Hexadecimal Guide: Why Developers Use Base-16 Every Day

May 28, 20266 min read

What Is Hexadecimal?

Hexadecimal (hex) is a base-16 number system. It uses sixteen distinct symbols: the digits 0 through 9 and the letters A through F. The letters represent decimal values 10 through 15.

Hex Digit0123456789ABCDEF
Decimal0123456789101112131415

Each position in a hex number represents a power of 16. For example:

2A3 = 2 × 16² + 10 × 16¹ + 3 × 16⁰
    = 512 + 160 + 3
    = 675 (decimal)

Programmers write hex values with a 0x prefix in most languages (0xFF) or a # prefix in CSS (#FF5733). These prefixes tell the reader and the compiler that the number is base-16, not base-10.

Why Hexadecimal?

Hex exists for one reason: it makes binary readable. One hex digit maps exactly to four binary digits (bits). This means a byte — 8 bits — always becomes exactly two hex digits.

Binary: 1111 1010
Hex:      F    A
Result: 0xFA

Compare that to the decimal equivalent: 250 tells you nothing about which bits are set. The hex value FA shows you immediately that the high nibble is 1111 and the low nibble is 1010.

This one-to-four mapping is why hex won out over octal (base-8) in modern computing. Octal groups bits in threes, which doesn't align cleanly with 8-bit, 16-bit, or 32-bit boundaries. Hex aligns perfectly with all of them.

Hex in Everyday Programming

CSS Color Values

Every web developer encounters hex daily through CSS colors. A six-digit hex color specifies red, green, and blue channels, each ranging from 00 to FF (0 to 255).

.hot-pink  { color: #FF69B4; }  /* R=255, G=105, B=180 */
.deep-blue { color: #003366; }  /* R=0,   G=51,  B=102  */

Modern CSS also supports 8-digit hex with an alpha channel:

.semi-transparent { color: #FF573380; }  /* 50% opacity */

Memory Addresses and Debugging

When you print a pointer in C, C++, or Rust, the output is hex. Debuggers display memory addresses in hex. Profilers annotate stack traces with hex offsets.

printf("%p", &variable);  // Output: 0x7ffd4a3b2c10

Hex makes these addresses scannable. You can quickly spot alignment (addresses ending in 0 are 16-byte aligned) and page boundaries (addresses where multiple high bits change).

Byte Representation

When you inspect raw data — network packets, file headers, binary protocols — you see hex dumps. Tools like xxd, hexdump, and Wireshark display bytes as hex pairs.

00000000: 7f45 4c46 0201 0100 0000 0000 0000 0000  .ELF............
00000010: 0200 3e00 0100 0000 0040 0000 0000 0000  ..>......@......

Each pair of hex characters is one byte. If you can read hex, you can spot magic numbers (7f 45 4c 46 = ELF header), string literals, and structure layouts.

Bitmasks and Flags

Hex is the standard way to write bitmasks. Each hex digit controls exactly four bits.

const READ    = 0x4;  // 0100
const WRITE   = 0x2;  // 0010
const EXECUTE = 0x1;  // 0001

const FULL_ACCESS = READ | WRITE | EXECUTE;  // 0x7 (0111)

Conversion Techniques

Hex to Binary (and Back)

The fastest conversion: replace each hex digit with its 4-bit binary equivalent. Memorize this table and you'll never need a calculator.

HexBinaryHexBinary
0000081000
1000191001
20010A1010
30011B1011
40100C1100
50101D1101
60110E1110
70111F1111
Hex:    3    C    F
Binary: 0011 1100 1111

Hex to Decimal

Multiply each digit by its place value and add:

0xB2 = 11 × 16¹ + 2 × 16⁰ = 176 + 2 = 178

For quick mental math, remember these landmarks:

  • 0x10 = 16
  • 0x100 = 256 (one byte)
  • 0x1000 = 4,096
  • 0xFFFF = 65,535 (max 16-bit unsigned)

Decimal to Hex

Divide by 16 repeatedly, collecting remainders:

Decimal 43958 → Hex:
43958 ÷ 16 = 2747 remainder 6
2747  ÷ 16 = 171  remainder 11 (B)
171   ÷ 16 = 10   remainder 11 (B)
10    ÷ 16 = 0    remainder 10 (A)
Result: 0xAB B6

Common Pitfalls

Case Sensitivity

Hex digits A–F can be uppercase or lowercase. 0xFF and 0xff are identical. But some systems (particularly CSS) are case-sensitive in other ways, so pick a convention and stick with it. Most style guides prefer uppercase (0xFF, #FF5733).

Leading Zeros Matter

In hex, 0x1 and 0x01 are the same number, but they imply different things. 0x01 suggests a full byte (8 bits). When working with byte-level data, always pad to the correct width: one byte = two hex digits.

Confusing Hex with Decimal

The number 10 means ten in decimal but sixteen in hex. Always check the prefix. A missing 0x or # can cause silent bugs, especially in configuration files.

JavaScript Octal Trap

In JavaScript, a leading zero on an integer literal used to mean octal in sloppy mode. While modern JS uses 0o for octal and 0x for hex, legacy code may still surprise you. Always use explicit prefixes.

0x10  // 16 (hex) — intended
010   // 8  (octal) — likely a mistake

Key Takeaways

  • Hexadecimal is base-16, using digits 0–9 and A–F
  • One hex digit equals exactly four binary digits — this is why hex replaced octal
  • You encounter hex in CSS colors, memory addresses, debug output, and byte dumps
  • The hex-to-binary table (16 entries) is worth memorizing for daily programming
  • Always use explicit prefixes (0x or #) to avoid confusion with decimal
  • Pad hex values to the correct byte width to prevent subtle bugs

Try It Yourself

Convert between hex, binary, octal, and decimal using our free Number Base Converter. Working with CSS colors? Check the Color Converter to translate hex colors to RGB and HSL.