Data Representation
Introduction
Computers store and process bits — zeros and ones. Everything else — integers, text, sensor readings, program instructions — is an encoding agreed by hardware and software. If you misread an encoding (signed vs unsigned, endianness, float format), values look wrong even when the wiring is perfect.
This article covers number systems, binary arithmetic, two's complement, character codes, parity, and IEEE floating point — the representations you need for embedded registers, communication protocols, and debugging.
Number systems
| Base | Digits | Prefix | Typical use |
|---|---|---|---|
| Binary | 0, 1 | % or 0b |
Hardware, registers |
| Decimal | 0–9 | none | Human reading |
| Hexadecimal | 0–9, A–F | 0x |
Compact binary shorthand (4 bits per digit) |
Binary ↔ hex
Each hex digit = 4 bits:
1 | |
Leading zeros can be dropped: 1001000110100 = same value.
Binary ↔ decimal
Sum powers of two where bit = 1:
1 | |
Decimal → binary
Find the largest power of two that fits, subtract, repeat:
1 2 3 4 | |
Signed integers: two's complement
Fixed-width integers (e.g. 8 bits) need a rule for negative numbers. Two's complement is standard on virtually all MCUs.
Rule: If the most significant bit (MSB) is 1, the value is negative.
To decode negative 10110111 (8 bits):
- Invert bits:
01001000 - Add 1:
01001001= 73₁₀ - Apply sign: −73
Range for n bits: −2ⁿ⁻¹ to 2ⁿ⁻¹ − 1 (e.g. 8 bits: −128 to +127).
Hex and signed
0xFF as unsigned 8-bit = 255. As signed 8-bit = −1. Always know the type your code uses.
ASCII and text
ASCII maps characters to 7-bit codes (often stored in 8 bits):
| Char | Decimal | Binary (7-bit) |
|---|---|---|
| H | 72 | 1001000 |
| a | 97 | 1100001 |
| l | 108 | 1101100 |
| o | 111 | 1101111 |
"Hello" is a sequence of byte values in memory. Modern systems also use UTF-8 for international text; embedded protocols often stick to ASCII for simplicity.
Parity bit
An even parity bit prepended so the total number of 1-bits is even — used for simple error detection on serial links:
1 | |
IEEE 754 floating point (32-bit)
Real numbers (3.14, 0.5625) use sign, exponent, and mantissa (fraction).
Example: 0.5625₁₀
1 2 | |
| Field | Bits | Value for 0.5625 |
|---|---|---|
| Sign | 1 | 0 (positive) |
| Exponent | 8 | −1 + 127 bias = 126 |
| Mantissa | 23 | 001000... (implicit leading 1 omitted) |
Embedded tip: avoid float on tiny MCUs without FPU if possible — use fixed-point (value * 1000 as integer).
Endianness
Multi-byte values can be stored little-endian (least significant byte first) or big-endian (MSB first). ARM Cortex-M is typically little-endian. Network protocols often use big-endian (network byte order). Mixing them scrambles values over 255.
Relevant topics
- Introduction to computer systems
- Sampling and A/D conversion
- Serial communication protocols
- Two's complement (Wikipedia)
- IEEE 754 (Wikipedia)
Starting points
- Convert
0x2Ato decimal and binary by hand; verify with a calculator. - Interpret
0xFFas uint8_t vs int8_t in C — print both. - Encode your initials in ASCII hex (e.g.
M= 0x4D). - Inspect a float's bytes in memory (
memcpytouint32_t) to see IEEE layout.
Focus points
- Always know signed vs unsigned when reading register dumps.
- Hex is for humans — the machine sees binary;
0xis documentation convenience. - Float has rounding — do not use
==on computed floats; use epsilon compares. - Endianness matters in protocols and multi-byte sensor data.
Key points
- Binary, decimal, and hex are views of the same integer values.
- Two's complement encodes signed integers in fixed bit width.
- ASCII encodes characters; parity adds simple error detection.
- IEEE 754 encodes floating point; mind performance on MCUs without FPU.