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 of01111111111111110101101000101100
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 Digit | Decimal Value | Binary Value |
---|---|---|
0 | 0 | 0000 |
1 | 1 | 0001 |
2 | 2 | 0010 |
3 | 3 | 0011 |
4 | 4 | 0100 |
5 | 5 | 0101 |
6 | 6 | 0110 |
7 | 7 | 0111 |
8 | 8 | 1000 |
9 | 9 | 1001 |
A | 10 | 1010 |
B | 11 | 1011 |
C | 12 | 1100 |
D | 13 | 1101 |
E | 14 | 1110 |
F | 15 | 1111 |
Positional Values (Powers of 16)
Just like other number systems, hex uses positional notation:
Position | Power | Value | Example Use |
---|---|---|---|
0 | 16⁰ | 1 | Units |
1 | 16¹ | 16 | Sixteens |
2 | 16² | 256 | Bytes (0-255) |
3 | 16³ | 4,096 | Memory pages |
4 | 16⁴ | 65,536 | 16-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)
Binary | Hex | Decimal |
---|---|---|
0000 | 0 | 0 |
0001 | 1 | 1 |
0010 | 2 | 2 |
0011 | 3 | 3 |
0100 | 4 | 4 |
0101 | 5 | 5 |
0110 | 6 | 6 |
0111 | 7 | 7 |
1000 | 8 | 8 |
1001 | 9 | 9 |
1010 | A | 10 |
1011 | B | 11 |
1100 | C | 12 |
1101 | D | 13 |
1110 | E | 14 |
1111 | F | 15 |
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 Name | Hex Code | RGB Values | Description |
---|---|---|---|
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)
Hex | Decimal | Hex | Decimal | Hex | Decimal | Hex | Decimal |
---|---|---|---|---|---|---|---|
00 | 0 | 40 | 64 | 80 | 128 | C0 | 192 |
10 | 16 | 50 | 80 | 90 | 144 | D0 | 208 |
20 | 32 | 60 | 96 | A0 | 160 | E0 | 224 |
30 | 48 | 70 | 112 | B0 | 176 | F0 | 240 |
3F | 63 | 7F | 127 | BF | 191 | FF | 255 |
Common Hex Values in Computing
Hex Value | Decimal | Common Use |
---|---|---|
0x00 | 0 | Null/empty |
0xFF | 255 | Maximum byte value |
0x7F | 127 | Maximum signed byte |
0x80 | 128 | Minimum negative signed byte |
0xFFFF | 65,535 | Maximum 16-bit value |
0x10000 | 65,536 | 64KB boundary |
0xDEADBEEF | 3,735,928,559 | Magic number for debugging |
0xCAFEBABE | 3,405,691,582 | Java class file signature |
Color Hex Quick Reference
Color | Hex Code | RGB 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.