Fundamentals 7 min read

9 Essential C Utility Snippets Every Embedded Engineer Should Know

This article presents nine powerful C utility code examples—including a circular buffer, custom assertions, bit reversal, fixed‑point arithmetic, endianness conversion, bit masks, timer handling, binary search, and a simple bitset—explaining their purpose and demonstrating how they can improve performance and maintainability in embedded system development.

Liangxu Linux
Liangxu Linux
Liangxu Linux
9 Essential C Utility Snippets Every Embedded Engineer Should Know

1. Circular Buffer

A circular buffer implements a fixed‑size FIFO queue without moving data. It uses head and tail indices that wrap around using modulo arithmetic, making push and pop operations O(1). This pattern is common for UART receive buffers or any streaming data source.

typedef struct {
    int buffer[SIZE];   // storage array, SIZE must be a power of two for optimal modulo
    int head;           // index of next write position
    int tail;           // index of next read position
    int count;          // number of elements currently stored
} CircularBuffer;

void push(CircularBuffer *cb, int data) {
    if (cb->count < SIZE) {
        cb->buffer[cb->head] = data;
        cb->head = (cb->head + 1) % SIZE;
        cb->count++;
    }
    // else: buffer full – could handle overflow here
}

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; // sentinel for empty buffer
}

2. Assertion Macro

The macro provides a lightweight runtime check that is compiled out when NDEBUG is defined. When a condition fails, assert_failed prints the source file and line number, which aids debugging in embedded builds where standard assert may be unavailable.

#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);
    // optional: halt CPU, blink LED, or log to serial port
}

3. Bit Reversal

This function reverses the order of bits in an unsigned integer. It is useful for protocols that transmit least‑significant bits first or for hardware peripherals that expect reversed bit patterns.

unsigned int reverse_bits(unsigned int num) {
    unsigned int numOfBits = sizeof(num) * 8;
    unsigned int reverseNum = 0;
    for (unsigned int i = 0; i < numOfBits; i++) {
        if (num & (1u << i)) {
            reverseNum |= (1u << ((numOfBits - 1) - i));
        }
    }
    return reverseNum;
}

4. Fixed‑Point Arithmetic

Fixed‑point representation stores fractional values as integers scaled by 2^FIXED_SHIFT. The macros convert between floating‑point and fixed‑point, and fixed_multiply performs multiplication without overflow by using a wider intermediate type.

#include <stdint.h>

typedef int16_t fixed_t;          // 16‑bit signed fixed‑point
#define FIXED_SHIFT 8               // 8 fractional bits (Q8.8 format)
#define FLOAT_TO_FIXED(f) ((fixed_t)((f) * (1 << FIXED_SHIFT)))
#define FIXED_TO_FLOAT(f) ((float)(f) / (1 << FIXED_SHIFT))

fixed_t fixed_multiply(fixed_t a, fixed_t b) {
    // Promote to 32‑bit to avoid overflow, then shift back
    return (fixed_t)(((int32_t)a * (int32_t)b) >> FIXED_SHIFT);
}

5. Endianness Conversion

Swaps the two bytes of a 16‑bit value, converting between big‑endian and little‑endian representations. For larger widths, similar byte‑wise shifts can be applied.

uint16_t swap_bytes(uint16_t value) {
    return (value >> 8) | (value << 8);
}

6. Bit Masks

A macro that generates a mask with a single bit set. It simplifies creating masks for register fields or flag bits.

#define BIT_MASK(bit) (1U << (bit))

7. Timer Counting (AVR)

Typical pattern for configuring an AVR hardware timer and reading its current count register ( TCNT1). The example omits specific prescaler settings, which must be chosen according to the desired time base.

#include <avr/io.h>

void setup_timer(void) {
    // Example: configure Timer/Counter1 in CTC mode, prescaler = 64
    TCCR1B = (1 << WGM12) | (1 << CS11) | (1 << CS10);
    OCR1A = 0xFFFF; // top value (optional)
}

uint16_t read_timer(void) {
    return TCNT1;   // current 16‑bit count
}

8. Binary Search

Classic O(log n) search on a sorted integer array. Returns the index of the 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;
        if (arr[mid] == target) {
            return mid;
        } else if (arr[mid] < target) {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }
    return -1; // not found
}

9. Simple Bitset

A lightweight bitset that stores up to 32 flags in a single uint32_t. Functions allow setting a bit and querying its value.

#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;
}

These nine snippets illustrate frequently used low‑level utilities for embedded C development, helping to reduce code size, improve execution speed, and increase readability.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

c++Data Structuresembeddedutilitiesbit manipulation
Liangxu Linux
Written by

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.)

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.