In looking for circular buffer code to reuse, I've come across a use of char which confuses me
typedef struct CircularBuffer
{
void *buffer; // data buffer
void *buffer_end; // end of data buffer
size_t capacity; // maximum number of items in the buffer
size_t count; // number of items in the buffer
size_t sz; // size of each item in the buffer
void *head; // pointer to head
void *tail; // pointer to tail
} CircularBuffer;
void cb_push_back(CircularBuffer *cb, const void *item)
{
if(cb->count == cb->capacity)
// handle error
memcpy(cb->head, item, cb->sz);
////////////// here's the part I don't understand //////////
cb->head = (char*)cb->head + cb->sz;
//////////////////////////////////////////////////////////
if(cb->head == cb->buffer_end)
cb->head = cb->buffer;
cb->count++;
}
Why cast this void pointer to a char? Is this some sort of C idiom (I have very limted C expereience)? A away convenient way to increment a pointer perhaps?
The use of a char for the position pointer comes up again in some different buffer code as well:
/**< Circular Buffer Types */
typedef unsigned char INT8U;
typedef INT8U KeyType;
typedef struct
{
INT8U writePointer; /**< write pointer */
INT8U readPointer; /**< read pointer */
INT8U size; /**< size of circular buffer */
KeyType keys[0]; /**< Element of ciruclar buffer */
} CircularBuffer;
Again, this looks like some sort of handy trick that C programmers know about, something about pointers being easy to manipulate if they're chars. But I'm really just speculating.
The cast to char *
is to make pointer arithmetic perform correctly if you want to move the pointer in one-byte steps; this always works because char
have, by definition, the size of 1 byte. Pointer arithmetic with void *
pointers, instead, is not defined by the C standard, because void
doesn't specify a size for a single item.
Another common C idiom (related to this) is to use unsigned char *
when you want to access some memory as "raw bytes" (the unsigned
type lets you access the unsigned value of each byte without casts); it's often used also typedef
ed (something along the lines of typedef unsigned char byte;
) to make it extra clear that you don't want to interpret the memory as characters, but as raw bytes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With