Circular Queue in C for an embedded project I wrote a simple circular queue. (in order to store characters because of the fact, that I am using UART through the DMA and sometimes my printf's override each other)
I am looking for some review, though my testfile was successful I have the feeling I've overseen something and the queue might be buggy at some point.
I appreciate any kind of critics, ideas or improvements

Header File:

#ifndef __QUEUEH
#define __QUEUEH

typedef struct queue {

    unsigned int head;
    unsigned int tail;
    unsigned char* buf;
    unsigned int bufSize;
    unsigned int freeSpace;
    unsigned int occuSpace;
    unsigned char initialized;

} queue_t;

extern int queue_init(queue_t* q, unsigned char* buf, unsigned int bufSize);
extern int enqueue(queue_t* q, unsigned char* element, unsigned int size);
extern int dequeue(queue_t* q, unsigned char* str, int strMaxSize);
// change to static
extern int printQueue(queue_t* q);
#endif


C-File:

#include "queue.h"
#if !defined bool
typedef unsigned char bool;
#endif

extern int queue_init(queue_t* q, unsigned char* buf, unsigned int bufSize) {
    q-&gt;head = -1;
    q-&gt;tail = 0;
    q-&gt;buf = buf;
    q-&gt;bufSize = bufSize;
    q-&gt;freeSpace = bufSize;
    q-&gt;occuSpace = 0;
    q-&gt;initialized = 1;
    return 0;
}

static inline bool moveTail(queue_t* q) {
    q-&gt;occuSpace = q-&gt;occuSpace - 2 - (q-&gt;buf)[q-&gt;tail];
    q-&gt;freeSpace = q-&gt;freeSpace + 2 + (q-&gt;buf)[q-&gt;tail];
    q-&gt;tail = (q-&gt;tail + (q-&gt;buf)[q-&gt;tail]+2) % (q-&gt;bufSize);
    return 0;
}

static inline bool enoughSpaceAvailable(queue_t* q, unsigned int size) {
    if(q-&gt;freeSpace &lt; size+2)
        return 0;
    return 1;
}

extern int enqueue(queue_t* q, unsigned char* element, unsigned int size) {

    if(size==0)
        return -5;
    else if(size&gt;q-&gt;bufSize-2)
        return -8;

    while(!enoughSpaceAvailable(q,size))
            moveTail(q);

    q-&gt;occuSpace = q-&gt;occuSpace + 2 + size;
    q-&gt;freeSpace = q-&gt;freeSpace - 2 - size;
    q-&gt;head = (q-&gt;head+1)%(q-&gt;bufSize);
    (q-&gt;buf)[q-&gt;head] = size;
    for(int i = 0; i&lt;size; i++) {
        q-&gt;head = (q-&gt;head+1)%(q-&gt;bufSize);
        (q-&gt;buf)[q-&gt;head] = element[i];
    }
    q-&gt;head = (q-&gt;head+1)%(q-&gt;bufSize);
    (q-&gt;buf)[q-&gt;head] = size;
    return 0;
}

extern int dequeue(queue_t* q, unsigned char* str, int strMaxSize) {

    int len = q-&gt;buf[q-&gt;tail];
    if(q-&gt;freeSpace == q-&gt;bufSize) return -6; else if(strMaxSize&lt;len) return -7;

    for(int j=0; j&lt;len; j++) {
        str[j] = q-&gt;buf[(q-&gt;tail+1+j)%(q-&gt;bufSize)];
    }
    moveTail(q);
    return 0;
}
Functionality unclear

Post discusses "... circular queue. (in order to store characters ...". 

After digging deeply into code I now realize the goal is not to enqueue a character and then a character and so on.  Instead the goal is to enqueue a group of characters, then another group and so on.

This is not clear from the the post and importantly, it is not clear from the .h file.

Documentation

The .h file, as a public interface deserves  as least a little documentation/comment per function.

Nonuniform name-space

__QUEUEH, queue, queue_init, enqueue, dequeue, printQueue would benefit with a more  common naming convention to clearly show that they belong together.

Consider QUEUE_H, queue, queue_init, queue_set, queue_get, queue_print

queue_t

Information hiding: The members of queue_t do not need to be in the .h file.  The below is sufficient.  If external code needs to read any of these members, I recommend a function to do so.

typedef struct queue queue_t;


Put the full struct queue definition in the .c file.

.initialized is a good candidate for bool.

// unsigned char initialized;
bool initialized;


Unnecessary item in .h

As a static function, printQueue does not belong in the .h file.  Remove it.



Avoid standard library collisions

The below conflicts with bool from stdbool.h.  Do not re-invent the standard boolean type.

// #if !defined bool
// typedef unsigned char bool;
// #endif
#include &lt;stdbool.h&gt;


queue_init()

Why set .head, an unsigned type, to a negative value?  Set to a unsigned value.

// q-&gt;head = -1;
q-&gt;head = -1u;


moveTail()

The role of magic number 2 is unclear here and in many of the functions.  Explain the 2.

Unexpected strMaxSize

How does reading the data in the queue relate to the length of anything?

int len = q-&gt;buf[q-&gt;tail];


The role of strMaxSize in dequeue() is unclear.

Hmmmmm

After more review it looks like the first character in a group of characters is the group's length.

enoughSpaceAvailable()

Avoid overflow: size+2 can overflow - this code has no control over the value of size.  Consider a more robust test.

// if(q-&gt;freeSpace &lt; size+2) return 0;
//return 1;

return q-&gt;freeSpace &gt; size &amp;&amp; q-&gt;freeSpace - size &gt;= 2;


const

Many functions would benefit with a const queue_t *

// enoughSpaceAvailable(queue_t* q, unsigned int size)
enoughSpaceAvailable(const queue_t* q, unsigned int size)


3 to do the job of 2

Unclear why code uses .bufSize, .freeSpace, .occuSpace when only 2 are needed.  I'd expect .bufSize, .occuSpace are sufficient here.



Overall

Code lacks documentation to indicate the overall coding goals.  Without that, there is too much to discover.

I still do not know how to use best these calls.  Will enqueue(q, "", 0); cause havoc?   How to test is the queue is empty? What are all the error codes?  Why are errors negative?  What does a positive response mean?  

To me, it is  the un-posted testfile contains too much information there and not enough here.

This code deserves an update and then a following review.



Sample alternate aqueue.h.
I avoided "queue" as too generic and used "aqueue".

/*
 * aqueue: queue of groups of binary data
 */

#ifndef AQUEUE_H
#define AQUEUE_H

typedef struct aqueue aqueue_t;

// All functions that return `int` return 0 on success.

/*
 * Initialize the queue with the buffer to use and its size.
 * Size [4..UINT_MAX]
 * Return TBD with invalid parameter values.
 */
int aqueue_init(aqueue_t* q, unsigned char* buf, unsigned bufSize);

/*
 * Insert a copy of what `data` points to.
 * Return TBD with insufficient space
 */
int queue_set(aqueue_t* q, const unsigned char* data, unsigned dataSize);

/*
 * Extract entry from the queue.
 * Return TBD when attempted with empty queue.
 * Return TBD when dataSize is too small.
 */
int aqueue_get(aqueue_t* q, unsigned char *data, unsigned dataSize);

/*
 * Queue empty?
 */
_Bool aqueue_empty(const aqueue_t* q);

/*
 * Get data without removing from the queue  (Peek)
 * Return TBD when attempted with empty queue.
 * Return TBD when dataSize is too small.
 */
int aqueue_top(const aqueue_t* q, unsigned char* data, unsigned dataSize);

#endif