Essential C Utility Code Snippets Every Embedded Developer Should Know
This article presents a curated collection of high‑impact C utility code examples—including a circular buffer, assertion macro, bit‑reversal function, fixed‑point arithmetic, endianness conversion, bit masks, timer handling, binary search, and a simple bitset—explaining their purpose and showing ready‑to‑use implementations for embedded systems.
Circular Buffer
A circular buffer implements a fixed‑size FIFO queue using a statically allocated array and two wrap‑around indices (head and tail). It is useful for streaming data such as UART reception where memory must be deterministic.
typedef struct {
int buffer[SIZE]; // storage, SIZE must be defined by the user
int head; // index of next write
int tail; // index of next read
int count; // number of valid elements (0 ≤ count ≤ SIZE)
} CircularBuffer;
/* Insert an element at the head. If the buffer is full the element is discarded. */
void push(CircularBuffer *cb, int data) {
if (cb->count < SIZE) {
cb->buffer[cb->head] = data;
cb->head = (cb->head + 1) % SIZE;
cb->count++;
}
}
/* Remove and return the element at the tail. Returns –1 when empty. */
int pop(CircularBuffer *cb) {
if (cb->count > 0) {
int data = cb->buffer[cb->tail];
cb->tail = (cb->tail + 1) % SIZE;
cb->count--;
return data;
}
return -1; // buffer empty
}Assertion Macro
The macro enables runtime checks in debug builds while removing the overhead in release builds. When NDEBUG is not defined, a failed assertion calls assert_failed with file and line information.
#define assert(expression) ((void)0) /* default: no‑op */
#ifndef NDEBUG
#undef assert
#define assert(expression) ((expression) ? (void)0 : assert_failed(__FILE__, __LINE__))
#endif
void assert_failed(const char *file, int line) {
printf("Assertion failed at %s:%d
", file, line);
// user‑defined error handling can be added here
}Bit Reversal
This function reverses the order of bits in an unsigned integer. It is often required by communication protocols that transmit least‑significant bits first.
unsigned int reverse_bits(unsigned int num) {
unsigned int numOfBits = sizeof(num) * 8; // total bits in the type
unsigned int reverseNum = 0;
for (unsigned int i = 0; i < numOfBits; i++) {
if (num & (1u << i)) {
reverseNum |= (1u << ((numOfBits - 1) - i));
}
}
return reverseNum;
}Fixed‑Point Arithmetic
Fixed‑point representation replaces floating‑point operations on processors without an FPU. The example uses an 8‑bit fractional part (Q8 format).
#include <stdint.h>
typedef int16_t fixed_t; // 16‑bit signed fixed‑point value
#define FIXED_SHIFT 8 // number of fractional bits
#define FLOAT_TO_FIXED(f) ((fixed_t)((f) * (1 << FIXED_SHIFT)))
#define FIXED_TO_FLOAT(f) ((float)(f) / (1 << FIXED_SHIFT))
/* Multiply two Q8 numbers and keep the result in Q8 format. */
fixed_t fixed_multiply(fixed_t a, fixed_t b) {
return (fixed_t)(((int32_t)a * (int32_t)b) >> FIXED_SHIFT);
}Endianness Conversion
Swaps the high and low bytes of a 16‑bit value, converting between big‑endian and little‑endian representations.
#include <stdint.h>
uint16_t swap_bytes(uint16_t value) {
return (value >> 8) | (value << 8);
}Bit Masks
Utility macro that creates a mask with a single bit set at the specified position.
#define BIT_MASK(bit) (1U << (bit))Timer Counting (AVR Example)
Shows how to include the AVR I/O header, configure a hardware timer, and read its current count register ( TCNT1). The code is portable to any AVR MCU that provides TCNT1.
#include <avr/io.h>
/* Configure Timer/Counter1 for a desired prescaler and mode. */
void setup_timer(void) {
// Example: normal mode, prescaler = 64
TCCR1B = (1 << CS11) | (1 << CS10); // set prescaler bits
TCNT1 = 0; // reset counter
}
/* Return the current 16‑bit count value. */
uint16_t read_timer(void) {
return TCNT1;
}Binary Search
Classic O(log n) search algorithm for a sorted integer array. Returns the index of target or –1 if not found.
int binary_search(const int arr[], int size, int target) {
int left = 0, right = size - 1;
while (left <= right) {
int mid = left + (right - left) / 2; // avoid overflow
if (arr[mid] == target) {
return mid;
} else if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1; // not found
}Simple Bitset
A lightweight structure that stores up to 32 boolean flags in a single 32‑bit integer. Provides functions to set and query individual bits.
#include <stdint.h>
typedef struct {
uint32_t bits; // each bit represents a flag
} Bitset;
void set_bit(Bitset *bs, int bit) {
bs->bits |= (1U << bit);
}
int get_bit(const Bitset *bs, int bit) {
return (bs->bits >> bit) & 1U;
}Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Liangxu Linux
Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
