Skip to main content

Hexadecimal Number System: Base-16 for Memory and Colors

What is Hexadecimal?

Hexadecimal (often shortened to "hex") is a base-16 number system that uses 16 different symbols: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F.

Think of hexadecimal as an extension of our normal counting system - but instead of stopping at 9 and moving to the next position, we continue with letters A through F to represent the values 10 through 15.

Decimal: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
Hex: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F

Why is Hexadecimal So Important?

Hexadecimal is everywhere in computing. Here's why it's become the standard:

1. Perfect Match with Computer Architecture

  • 1 hex digit = exactly 4 binary digits (bits)
  • 2 hex digits = exactly 8 bits = 1 byte
  • This makes hex incredibly efficient for representing binary data

2. Memory Addresses

  • All computer memory addresses are displayed in hex
  • Much more compact than binary, more meaningful than decimal
  • Example: 0x7FFF5A2C instead of 01111111111111110101101000101100

3. Color Codes in Web Development

  • RGB colors: #FF0000 (red), #00FF00 (green), #0000FF (blue)
  • Each pair of hex digits represents red, green, or blue intensity (0-255)

4. Debugging and Programming

  • Assembly language uses hex for addresses and values
  • Error messages often include hex codes
  • Low-level programming uses hex constants

5. Data Representation

  • Network protocols use hex for packet analysis
  • File formats often documented in hex
  • Cryptographic hashes displayed in hex

Understanding Hex Digits and Values

Hex Digit Mapping

Hex DigitDecimal ValueBinary Value
000000
110001
220010
330011
440100
550101
660110
770111
881000
991001
A101010
B111011
C121100
D131101
E141110
F151111

Positional Values (Powers of 16)

Just like other number systems, hex uses positional notation:

PositionPowerValueExample Use
016⁰1Units
116¹16Sixteens
216²256Bytes (0-255)
316³4,096Memory pages
416⁴65,53616-bit values

Converting Hex to Decimal: Step-by-Step

Example 1: Simple Conversion (2F₁₆)

Hex number: 2 F

Step 1: Identify positions and values
Position: 1 0
Hex digit: 2 F
Decimal value: 2 15
Power of 16: 16¹ 16⁰
Position value: 16 1

Step 2: Multiply each digit value by its position value
2 × 16 = 32
F × 1 = 15 × 1 = 15

Step 3: Add all results
32 + 15 = 47

Therefore: 2F₁₆ = 47₁₀

Example 2: Larger Number (A3C₁₆)

Hex number: A 3 C

Step 1: Convert hex digits to decimal values
A = 10, 3 = 3, C = 12

Step 2: Apply positional notation
Position: 2 1 0
Hex digit: A 3 C
Decimal: 10 3 12
Power of 16: 16² 16¹ 16⁰
Value: 256 16 1

Step 3: Calculate
10 × 256 = 2,560
3 × 16 = 48
12 × 1 = 12

Step 4: Sum
2,560 + 48 + 12 = 2,620

Therefore: A3C₁₆ = 2,620₁₀

Example 3: Four-Digit Hex (BEEF₁₆)

Hex number: B E E F

Converting each digit:
B = 11, E = 14, E = 14, F = 15

Positional calculation:
Position: 3 2 1 0
Hex: B E E F
Decimal: 11 14 14 15
Power: 16³ 16² 16¹ 16⁰
Value: 4,096 256 16 1

Calculation:
11 × 4,096 = 45,056
14 × 256 = 3,584
14 × 16 = 224
15 × 1 = 15

Total: 45,056 + 3,584 + 224 + 15 = 48,879

Therefore: BEEF₁₆ = 48,879₁₀

Converting Decimal to Hex: Repeated Division

Method: Divide by 16, Record Remainders

Just like other base conversions, we divide by the base (16) and collect remainders.

Example 1: Convert 47₁₀ to Hex

Step 1: 47 ÷ 16 = 2 remainder 15
Remainder 15 = F in hex

Step 2: 2 ÷ 16 = 0 remainder 2
Remainder 2 = 2 in hex

Step 3: Read remainders from bottom to top
2F₁₆

Therefore: 47₁₀ = 2F₁₆

Verification: 2×16 + F×1 = 32 + 15 = 47 ✓

Example 2: Convert 255₁₀ to Hex

255 ÷ 16 = 15 remainder 15  → F
15 ÷ 16 = 0 remainder 15 → F

Reading from bottom to top: FF₁₆

Therefore: 255₁₀ = FF₁₆

Verification: F×16 + F×1 = 15×16 + 15×1 = 240 + 15 = 255 ✓

Note: FF₁₆ = 255₁₀ is the maximum value for one byte!

Example 3: Convert 4,095₁₀ to Hex

4,095 ÷ 16 = 255 remainder 15  → F
255 ÷ 16 = 15 remainder 15 → F
15 ÷ 16 = 0 remainder 15 → F

Reading from bottom to top: FFF₁₆

Therefore: 4,095₁₀ = FFF₁₆

This is the maximum value for 12 bits (3 hex digits)

Binary to Hex Conversion: The Fast Way

Key insight: 1 hex digit = exactly 4 binary digits (bits)

This makes binary-to-hex conversion extremely simple.

Binary-to-Hex Mapping (4-bit groups)

BinaryHexDecimal
000000
000111
001022
001133
010044
010155
011066
011177
100088
100199
1010A10
1011B11
1100C12
1101D13
1110E14
1111F15

Example 1: Convert 11010111₂ to Hex

Step 1: Group binary digits into sets of 4 (from right to left)
1101 0111

Step 2: Convert each group using the mapping table
1101₂ = D₁₆
0111₂ = 7₁₆

Step 3: Combine
D7₁₆

Therefore: 11010111₂ = D7₁₆

Example 2: Convert 101101011110₂ to Hex

Step 1: Group into sets of 4 from right (add leading zeros if needed)
1011 0101 1110 → 1011 0101 1110

Step 2: Convert each group
1011₂ = B₁₆
0101₂ = 5₁₆
1110₂ = E₁₆

Step 3: Combine
B5E₁₆

Therefore: 101101011110₂ = B5E₁₆

Hex to Binary Conversion

Reverse process: Each hex digit converts to exactly 4 binary digits.

Example 1: Convert FA2₁₆ to Binary

Step 1: Convert each hex digit to 4-bit binary
F₁₆ = 1111₂
A₁₆ = 1010₂
2₁₆ = 0010₂

Step 2: Concatenate
1111 1010 0010

Step 3: Remove spaces (optional)
111110100010₂

Therefore: FA2₁₆ = 111110100010₂

Example 2: Convert CAFE₁₆ to Binary

C₁₆ = 1100₂
A₁₆ = 1010₂
F₁₆ = 1111₂
E₁₆ = 1110₂

Concatenate: 1100 1010 1111 1110 = 1100101011111110₂

Therefore: CAFE₁₆ = 1100101011111110₂

Web Development: Color Codes

Understanding RGB Hex Colors

Web colors use 6-digit hex codes representing Red, Green, Blue intensities:

Format: #RRGGBB
Where:
- RR = Red intensity (00 to FF = 0 to 255)
- GG = Green intensity (00 to FF = 0 to 255)
- BB = Blue intensity (00 to FF = 0 to 255)

Example 1: Pure Red (#FF0000)

Color: #FF0000

Breaking it down:
FF = 255₁₀ (maximum red)
00 = 0₁₀ (no green)
00 = 0₁₀ (no blue)

Result: Pure red color

Example 2: Purple (#800080)

Color: #800080

Breaking it down:
80 = 128₁₀ (medium red intensity)
00 = 0₁₀ (no green)
80 = 128₁₀ (medium blue intensity)

Red + Blue = Purple (magenta)

Example 3: Light Gray (#CCCCCC)

Color: #CCCCCC

Breaking it down:
CC = 204₁₀ (high red intensity)
CC = 204₁₀ (high green intensity)
CC = 204₁₀ (high blue intensity)

Equal amounts of R, G, B = Gray color

Common Color Examples

Color NameHex CodeRGB ValuesDescription
Black#000000(0,0,0)No color
White#FFFFFF(255,255,255)All colors
Red#FF0000(255,0,0)Pure red
Green#00FF00(0,255,0)Pure green
Blue#0000FF(0,0,255)Pure blue
Yellow#FFFF00(255,255,0)Red + Green
Cyan#00FFFF(0,255,255)Green + Blue
Magenta#FF00FF(255,0,255)Red + Blue

CSS Color Usage

/* Full 6-digit hex */
.red-text {
color: #ff0000;
}
.blue-bg {
background-color: #0000ff;
}

/* Short 3-digit hex (each digit repeated) */
.white {
color: #fff;
} /* Same as #FFFFFF */
.black {
color: #000;
} /* Same as #000000 */
.red {
color: #f00;
} /* Same as #FF0000 */

/* Semi-transparent (8-digit hex with alpha) */
.semi-red {
color: #ff000080;
} /* 50% transparent red */

Memory Addresses and Programming

Understanding Memory Addresses

Computer memory addresses are always displayed in hexadecimal because:

  • Much more compact than binary
  • Direct relationship to binary (4 bits = 1 hex digit)
  • Easy to see bit patterns and alignment

Example Memory Addresses

32-bit system addresses:
0x00000000 (start of memory)
0x08048000 (typical program start)
0x7FFFFFFF (end of user space)
0xFFFFFFFF (maximum 32-bit address)

64-bit system addresses:
0x0000000000000000 (start of memory)
0x00007FFF5A2C1000 (typical stack address)
0xFFFFFFFFFFFFFFFF (maximum 64-bit address)

Pointer Values in C/C++

#include <stdio.h>

int main() {
int number = 42;
int *pointer = &number;

printf("Value: %d\n", number); // 42
printf("Address: %p\n", (void*)pointer); // 0x7fff5a2c1000 (example)
printf("Address in hex: 0x%lX\n", (unsigned long)pointer);

return 0;
}

JavaScript Memory Debugging

// ArrayBuffer with hex view
const buffer = new ArrayBuffer(16);
const view = new DataView(buffer);

// Set some values
view.setUint32(0, 0xdeadbeef); // Famous hex value
view.setUint32(4, 0xcafebabe); // Another famous hex value

// Read as hex
console.log("First 4 bytes:", view.getUint32(0).toString(16).toUpperCase());
console.log("Next 4 bytes:", view.getUint32(4).toString(16).toUpperCase());

// Output:
// First 4 bytes: DEADBEEF
// Next 4 bytes: CAFEBABE

Programming Examples and Practical Usage

JavaScript: Working with Hex

// Converting between hex and decimal
const hexValue = 0xff; // 255 in decimal
console.log(`Hex 0xFF = Decimal ${hexValue}`);

// Converting numbers to hex strings
const decimal = 255;
const hexString = decimal.toString(16); // "ff"
const hexStringUpper = decimal.toString(16).toUpperCase(); // "FF"
console.log(`Decimal ${decimal} = Hex ${hexStringUpper}`);

// Converting hex strings to decimal
const hexStr = "FF";
const decimalValue = parseInt(hexStr, 16); // 255
console.log(`Hex ${hexStr} = Decimal ${decimalValue}`);

// Working with colors
function hexToRgb(hex) {
// Remove # if present
hex = hex.replace("#", "");

// Parse RGB components
const r = parseInt(hex.substr(0, 2), 16);
const g = parseInt(hex.substr(2, 2), 16);
const b = parseInt(hex.substr(4, 2), 16);

return { r, g, b };
}

function rgbToHex(r, g, b) {
// Convert each component to hex and pad with zeros
const rHex = r.toString(16).padStart(2, "0");
const gHex = g.toString(16).padStart(2, "0");
const bHex = b.toString(16).padStart(2, "0");

return `#${rHex}${gHex}${bHex}`.toUpperCase();
}

// Examples
console.log(hexToRgb("#FF5733")); // { r: 255, g: 87, b: 51 }
console.log(rgbToHex(255, 87, 51)); // #FF5733

// Bitwise operations with hex
const flag1 = 0x01; // 00000001
const flag2 = 0x02; // 00000010
const flag3 = 0x04; // 00000100

const allFlags = flag1 | flag2 | flag3; // 0x07 = 00000111
console.log(`Combined flags: 0x${allFlags.toString(16).toUpperCase()}`);

// Check if specific flag is set
function hasFlag(value, flag) {
return (value & flag) === flag;
}

console.log(hasFlag(0x07, flag2)); // true
console.log(hasFlag(0x05, flag2)); // false

Python: Hex Operations

# Basic hex operations
hex_value = 0xFF # 255 in decimal
print(f"Hex 0xFF = Decimal {hex_value}")

# Converting to hex string
decimal = 255
hex_string = hex(decimal) # '0xff'
hex_upper = f"0x{decimal:02X}" # '0xFF'
print(f"Decimal {decimal} = {hex_upper}")

# Converting from hex string
hex_str = "FF"
decimal_value = int(hex_str, 16)
print(f"Hex {hex_str} = Decimal {decimal_value}")

# Working with bytes and hex
data = b"Hello"
hex_representation = data.hex() # '48656c6c6f'
print(f"'{data.decode()}' in hex: {hex_representation}")

# Convert back from hex
hex_data = "48656c6c6f"
original_bytes = bytes.fromhex(hex_data)
print(f"Hex {hex_data} = '{original_bytes.decode()}'")

# Color manipulation
def hex_to_rgb(hex_color):
"""Convert hex color to RGB tuple"""
hex_color = hex_color.lstrip('#')
return tuple(int(hex_color[i:i+2], 16) for i in (0, 2, 4))

def rgb_to_hex(r, g, b):
"""Convert RGB values to hex color"""
return f"#{r:02X}{g:02X}{b:02X}"

# Examples
rgb = hex_to_rgb("#FF5733")
print(f"#FF5733 = RGB{rgb}") # (255, 87, 51)

hex_color = rgb_to_hex(255, 87, 51)
print(f"RGB(255, 87, 51) = {hex_color}")

# Memory-like operations
def dump_hex(data, bytes_per_line=16):
"""Display data in hex format like a memory dump"""
for i in range(0, len(data), bytes_per_line):
chunk = data[i:i + bytes_per_line]

# Address
address = f"{i:08X}:"

# Hex bytes
hex_bytes = ' '.join(f"{b:02X}" for b in chunk)
hex_bytes = hex_bytes.ljust(bytes_per_line * 3 - 1)

# ASCII representation
ascii_chars = ''.join(chr(b) if 32 <= b < 127 else '.' for b in chunk)

print(f"{address} {hex_bytes} |{ascii_chars}|")

# Example usage
sample_data = b"Hello, World! This is a hex dump example."
dump_hex(sample_data)

C/C++: Low-Level Hex Usage

#include <stdio.h>
#include <stdint.h>

int main() {
// Hex literals
uint32_t magic_number = 0xDEADBEEF;
uint16_t port = 0x1F90; // Port 8080 in decimal

printf("Magic number: 0x%08X (%u)\n", magic_number, magic_number);
printf("Port: 0x%04X (%u)\n", port, port);

// Bit manipulation with hex
uint8_t flags = 0x00;

// Set flags using hex masks
flags |= 0x01; // Set bit 0
flags |= 0x04; // Set bit 2
flags |= 0x10; // Set bit 4

printf("Flags: 0x%02X (binary: ", flags);
for (int i = 7; i >= 0; i--) {
printf("%d", (flags >> i) & 1);
}
printf(")\n");

// Memory dump
char data[] = "Hello";
printf("Memory dump of '%s':\n", data);

for (size_t i = 0; i < sizeof(data); i++) {
printf("data[%zu]: 0x%02X ('%c')\n",
i, (unsigned char)data[i],
data[i] ? data[i] : '.');
}

return 0;
}

Network and System Programming

IP Address Representation

import socket
import struct

# Convert IP address to hex
def ip_to_hex(ip_string):
"""Convert IP address string to hex representation"""
# Convert to 32-bit integer
ip_int = struct.unpack("!I", socket.inet_aton(ip_string))[0]
return f"0x{ip_int:08X}"

def hex_to_ip(hex_value):
"""Convert hex value back to IP address"""
if isinstance(hex_value, str):
ip_int = int(hex_value, 16)
else:
ip_int = hex_value

return socket.inet_ntoa(struct.pack("!I", ip_int))

# Examples
ip = "192.168.1.1"
hex_ip = ip_to_hex(ip)
print(f"IP {ip} = {hex_ip}") # 0xC0A80101

back_to_ip = hex_to_ip(hex_ip)
print(f"Hex {hex_ip} = IP {back_to_ip}")

MAC Address Formatting

def format_mac_address(mac_bytes):
"""Format MAC address bytes as hex string"""
return ':'.join(f"{b:02X}" for b in mac_bytes)

def parse_mac_address(mac_string):
"""Parse MAC address string to bytes"""
return bytes(int(part, 16) for part in mac_string.split(':'))

# Example
mac_bytes = b'\x00\x1B\x44\x11\x3A\xB7'
mac_string = format_mac_address(mac_bytes)
print(f"MAC: {mac_string}") # 00:1B:44:11:3A:B7

parsed_mac = parse_mac_address(mac_string)
print(f"Parsed back: {parsed_mac.hex().upper()}")

Debugging with Hex

Memory Dump Analysis

def analyze_hex_dump(hex_string):
"""Analyze a hex dump and extract information"""
# Remove spaces and convert to bytes
hex_clean = hex_string.replace(' ', '').replace('\n', '')
data = bytes.fromhex(hex_clean)

print(f"Total bytes: {len(data)}")
print(f"First 4 bytes as uint32: 0x{int.from_bytes(data[:4], 'big'):08X}")

# Look for ASCII strings
ascii_str = ''.join(chr(b) if 32 <= b < 127 else '.' for b in data)
print(f"ASCII representation: {ascii_str}")

# Find null-terminated strings
strings = []
current_string = ""
for byte in data:
if 32 <= byte < 127: # Printable ASCII
current_string += chr(byte)
else:
if len(current_string) > 3: # Only keep strings longer than 3 chars
strings.append(current_string)
current_string = ""

if strings:
print("Found strings:", strings)

# Example usage
hex_data = "48656C6C6F20576F726C64210A00"
analyze_hex_dump(hex_data)

Quick Reference Tables

Hex to Decimal (0-255)

HexDecimalHexDecimalHexDecimalHexDecimal
000406480128C0192
1016508090144D0208
20326096A0160E0224
304870112B0176F0240
3F637F127BF191FF255

Common Hex Values in Computing

Hex ValueDecimalCommon Use
0x000Null/empty
0xFF255Maximum byte value
0x7F127Maximum signed byte
0x80128Minimum negative signed byte
0xFFFF65,535Maximum 16-bit value
0x1000065,53664KB boundary
0xDEADBEEF3,735,928,559Magic number for debugging
0xCAFEBABE3,405,691,582Java class file signature

Color Hex Quick Reference

ColorHex CodeRGB Values
Red#FF0000(255,0,0)
Green#00FF00(0,255,0)
Blue#0000FF(0,0,255)
White#FFFFFF(255,255,255)
Black#000000(0,0,0)
Gray#808080(128,128,128)
Silver#C0C0C0(192,192,192)
Yellow#FFFF00(255,255,0)

Common Mistakes and Troubleshooting

Mistake 1: Confusing Hex Letters

❌ Wrong: Thinking A=1, B=2, etc.
✅ Correct: A=10, B=11, C=12, D=13, E=14, F=15

Mistake 2: Case Sensitivity Issues

# Both are correct, but be consistent
hex_lower = 0xff # Lowercase
hex_upper = 0xFF # Uppercase

# String parsing is case-insensitive
int("ff", 16) # 255
int("FF", 16) # 255 (same result)

Mistake 3: Forgetting the 0x Prefix

// ❌ Unclear: Is this hex or decimal?
int value = 123;

// ✅ Clear: Obviously hex
int hex_value = 0x123; // 291 in decimal
int dec_value = 123; // 123 in decimal

Mistake 4: Color Code Format Issues

/* ❌ Wrong: Missing # symbol */
color: FF0000;

/* ✅ Correct: Include # prefix */
color: #ff0000;

/* ❌ Wrong: Invalid hex digits */
color: #GG0000;

/* ✅ Correct: Only use 0-9, A-F */
color: #ff0000;

Key Takeaways

Hex uses 16 digits (0-9, A-F) with positions as powers of 16
1 hex digit = 4 binary bits (perfect binary grouping)
2 hex digits = 1 byte (0-255 decimal values)
Main uses: Memory addresses, color codes, debugging, low-level programming
Web colors: 6-digit format #RRGGBB for red, green, blue intensities
Memory efficiency: Much more compact than binary, more meaningful than decimal
Programming: Essential for bit manipulation, pointer arithmetic, and system programming

Understanding hexadecimal is crucial for:

  • Web development: CSS colors and JavaScript bitwise operations
  • System programming: Memory addresses and low-level debugging
  • Network programming: IP addresses, MAC addresses, packet analysis
  • Graphics programming: Color manipulation and pixel data
  • Embedded systems: Register values and hardware communication
  • Cryptography: Hash values and encryption keys
  • Game development: Asset IDs and performance optimization

Hexadecimal serves as the bridge between human-readable numbers and computer binary data, making it an indispensable tool for any serious programmer or system administrator.