4

Given the desire to abstract the structure of a circular buffer from its content, and starting from the following code segments (courtesy of this wikipedia entry):

typedef struct
{ 
    int value;
} ElemType;

typedef struct
{
    int         size;      /* total number of elements */
    int         start;     /* index of oldest element */
    int         count;     /* index at which to write new element  */
    ElemType   *elements;  /* vector of elements */
} CircularBuffer;

void cbInit(CircularBuffer *cb, int size) {
    cb->size  = size;
    cb->start = 0;
    cb->count = 0;
    cb->elements = (ElemType *)calloc(cb->size, sizeof(ElemType));
}

How does one abstract the element type so that it is specified when an instance of the CircularBuffer is defined? My attempt thus far is as follows:

CircularBuffer *cbInit(uint16 size, void *element)
{
    CircularBuffer *buffer;

    buffer = malloc(sizeof(*buffer));

    if (buffer != NULL)
    {
        buffer->size = size;
        buffer->start = 0;
        buffer->count = 0;
        buffer->elements = (void *)calloc(size, sizeof(???));

        if (buffer->elements == NULL)
        {
            free(buffer);
            buffer = NULL;
        }
    }

    return buffer;
}

But I cannot figure out how to determine the size of an unknown type, which may be an int, a struct, or anything in between. Is what I am attempting to do even possible?

4
  • But you will be using pointers to those objects right? Pointers sizes are the same. sizeof(void*) Commented Nov 29, 2012 at 2:48
  • This is one of those things that C++ templates makes life so much easier. Here, you either need a raw memory buffer and pass in the size from the user. Or go completely with pointers. Commented Nov 29, 2012 at 2:48
  • The code in question is being used to buffer serial UART input on an embedded system. I had initially implemented the buffer using a doubly-linked list, but the overhead imposed by the structure was too great given the actual content of each node is a single char. I am seeking a middle ground where the code is generic enough for me to reuse, without too much overhead in terms of RAM usage. Commented Nov 29, 2012 at 3:10
  • you'd be better of just using a circular buffer of unsgined char (byte) if its for a UART. making it generic will cost you, and you'll be forever casting. The other approach is to macro magic generation of a circular buffer for each type you want. Commented Nov 29, 2012 at 3:39

1 Answer 1

7

As you've found out, you can't automatically tell the size of an unknown piece of data. You'll need either a fixed element type (void* would be a good generic choice), or have the user pass in the size of each element:

CircularBuffer *cbInit(uint16 size, int elementSize)
{
    ...
    buffer->elementSize = elementSize;
    buffer->elements    = calloc(size, elementSize);  
}
Sign up to request clarification or add additional context in comments.

2 Comments

The buffer will be storing homogeneous elements - that is, they will all be the same size. It is not true that sizeof(void*) is the size of a pointer to void? If so, what makes it a good generic choice, given it is compiler dependent, and does not correlate to the size of the element itself? Are you suggesting I use an array of pointers, each to a single element?
@Zack Yes, either an array of pointers, each to a single element; or you can store anything, but the user has to pass in the element size eplicitly. One of those two.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.