Ring Buffer
Wraparound mechanics, the three full/empty disambiguation strategies, and a byte ring buffer put/get — the UART driver interview classic.
Three pieces, and this is the one everyone warns is harder than it looks — a fixed-size circular buffer with a head and a tail that wrap back to 0 instead of running off the end.
Wraparound
#define SIZE 8
unsigned int advance(unsigned int idx) {
return (idx + 1) % SIZE; /* or (idx + 1) & (SIZE - 1) if SIZE is a power of 2 */
}The bitwise-AND form only works when SIZE is a power of 2 — x % SIZE and x & (SIZE - 1) are only equivalent in that specific case, since the mask only clears the exact bits that a power-of-2 modulus would wrap on.
The full-vs-empty problem
The actual hard part: head == tail alone is ambiguous — it means empty when nothing's been added yet, but it also means the exact same thing when the buffer has completely filled and wrapped back around to meet itself. Three ways to resolve it:
| Strategy | How it works |
|---|---|
| Count field | track element count separately — empty is count == 0, full is count == SIZE |
| Sacrifice a slot | never fill the last slot — full is (head+1) % SIZE == tail, one slot always wasted |
| Flag bit | an explicit is_full flag set on the write that causes head to catch tail |
A byte ring buffer — the UART pattern
typedef struct {
uint8_t buf[SIZE];
unsigned int head, tail, count;
} ring_buffer_t;
int put(ring_buffer_t *rb, uint8_t byte) {
if (rb->count == SIZE) return -1; /* full */
rb->buf[rb->tail] = byte;
rb->tail = (rb->tail + 1) % SIZE;
rb->count++;
return 0;
}
int get(ring_buffer_t *rb, uint8_t *out) {
if (rb->count == 0) return -1; /* empty */
*out = rb->buf[rb->head];
rb->head = (rb->head + 1) % SIZE;
rb->count--;
return 0;
}This is the UART RX-buffer shape directly: the interrupt handler calls put every time a byte arrives off the wire, and whatever's actually reading the device calls get to drain it — running independently, at different speeds, without either side needing to know anything about the other's timing.
Notes from readers
Comments — via GitHub