http://tath.eu/code/ring-buffer-in-c/

Ring buffer is very common and useful data structure, excellent for storing 
asynchronous data from multiple sources in embedded devices.

ringbuffer.h
// Simple prove-of-concept ring buffer
// Author: Adam Orcholski, www.tath.eu
#pragma once
 
// types
typedef struct ring_buffer_s
{
    unsigned char * data;   // pointer to external buffer
    int size;               // size of external buffer
    int head;               // index of free space in external buffer
    int tail;               // index of last item to be read
    int count;              // hold number of items stored but not read
} ring_buffer_t;
 
// interface
void RING_Init(ring_buffer_t * const buff_state, unsigned char * in_buffer, int buffer_size_in_bytes);
void RING_Reset(ring_buffer_t * const buff_state);      // note: does not clear external buffer
int  RING_IsEmpty(ring_buffer_t * const buff_state);    // return non-zero if buffer is empty
int  RING_IsFull(ring_buffer_t * const buff_state);     // return non-zero if buffer is full
int  RING_AddItem(ring_buffer_t * const buff_state, unsigned char new_item);            // return non-zero if buffer is full
int  RING_GetItem(ring_buffer_t * const buff_state, unsigned char * const out_item);    // return non-zero if buffer is empty

ringbuffer.c
// Simple prove-of-concept ring buffer
// Author: Adam Orcholski, www.tath.eu
 
#include <ringbuffer.h>
#include <assert.h>
 
 
// function definitions
void RING_Init(ring_buffer_t * const buff_state, unsigned char * in_buffer, int buffer_size_in_bytes)
{
    assert(0 != buff_state);
    assert(0 != in_buffer);
    assert(buffer_size_in_bytes > 0);
 
    buff_state->data = in_buffer;
    buff_state->size = buffer_size_in_bytes;
    buff_state->head = 0;
    buff_state->tail = 0;
    buff_state->count = 0;
}
 
void RING_Reset(ring_buffer_t * const buff_state)
{
    assert(0 != buff_state);
 
    buff_state->head = 0;
    buff_state->tail = 0;
    buff_state->count = 0;
}
 
// return non-zero value if buffer is empty
int  RING_IsEmpty(ring_buffer_t * const buff_state)
{
    int fBufferIsEmpty = 0;
 
    assert(0 != buff_state);
 
    if (0 == buff_state->count)
    {
        fBufferIsEmpty = 1;
    }
 
    return fBufferIsEmpty;
}
 
// return non-zero value if buffer is full
int  RING_IsFull(ring_buffer_t * const buff_state)
{
    int fBufferIsFull = 0;
 
    assert(0 != buff_state);
 
    if (buff_state->count >= buff_state->size)
    {
        fBufferIsFull = 1;
    }
 
    return fBufferIsFull;
}
 
// return non-zero value if buffer is full
int  RING_AddItem(ring_buffer_t * const buff_state, unsigned char new_item)
{
    int fBufferIsFull = 0;
 
    assert(0 != buff_state);
 
    fBufferIsFull = RING_IsFull(buff_state);
 
    if (!fBufferIsFull)
    {
        buff_state->data[buff_state->head] = new_item;
        buff_state->head++;
        buff_state->count++;
 
        if (buff_state->head >= buff_state->size)
        {
            buff_state->head = 0;
        }
    }
 
 
    return fBufferIsFull;
}
 
// return non-zero value if buffer is empty
int  RING_GetItem(ring_buffer_t * const buff_state, unsigned char * const out_item)
{
    int fBufferIsEmpty = 0;
 
    assert(0 != buff_state);
    assert(0 != out_item);
 
    fBufferIsEmpty = RING_IsEmpty(buff_state);
 
    if (!fBufferIsEmpty)
    {
        *out_item = buff_state->data[buff_state->tail];
        buff_state->tail++;
        buff_state->count--;
 
        if (buff_state->tail >= buff_state->size)
        {
            buff_state->tail = 0;
        }
    }
 
    return fBufferIsEmpty;
}

and example/test compiled in Microsoft Visual Studio:

main.c
// Simple prove-of-concept ring buffer example
// Author: Adam Orcholski, www.tath.eu
 
#include <stdio.h>
#include <ringbuffer.h>
 
#define BUFF_SIZE 4
unsigned char bufffeeer[BUFF_SIZE];
 
ring_buffer_t buff;
 
int main()
{
    RING_Init(&buff, bufffeeer, sizeof(bufffeeer));
 
    char c = 0;
 
    while (c != 'q')
    {
        static char write_char = 'a';
        c = getchar();
         
        int ret = 0;
 
        if (c == 'w')
        {
            ret = RING_AddItem(&buff, write_char);
            if (ret)
            {
                printf("buffer full\r\n");
            }
            else
            {
                printf("written char = %c\r\n", write_char);
            }
            write_char++;
            if (write_char == 'z') { write_char = 'a'; }
        }
        else if (c == 's')
        {
            char out;
            ret = RING_GetItem(&buff, &out);
            if (ret)
            {
                printf("buffer empty\r\n");
            }
            else
            {
                printf("read char = %c\r\n", out);
            }
        }
    }
 
    return 0;
}

Run example, and press W key to add item to buffer and S key to read last item. Press Q to quit.
