C: Is the syntax cleaner for generic data structures using void pointers?

I am currently writing a C stack implementation. I want it to use as little memory as possible and be as fast as possible, but still have all the data types I can throw on it, with multiples on each stack. I decided to use void pointers for this, and made it work relatively fast despite my rusty C. However, its actually pretty ugly.

For testing the stack, I am pushing integers with a loop. Actually passing int as a void pointer is a problem.

My first inclination was to use &

:

for (int i = 0; i < 20; i++){
    stack_push(s, &i); //s is the stack_t pointer
}

      

However, upon closer inspection, this clearly does not work, since i

each step is destructively updated. Each item on the stack ends with 20

.

Since then I have turned to a very ugly solution:

for (int i = 0; i < 20; i++){
    int* p = malloc(sizeof(void*));
    *p = i;
    stack_push(s, p);
}

      

This works, but two questions arise:

  • It's ugly

  • I need to worry about memory management for each stack item. (and for some reason manually moving the stack and freeing each item is still leaking memory ...)

Is there a better way to do this without wasting extra memory with concatenation and still fast? Thank.

+3


source to share


2 answers


If the types are going to be mixed, something needs to know what a type is.

If the client (or user) from the stack returns the types back to their correct form, then that's fine, but the size should still be stackable.

If the caller is aware of this, the interface might look like this:

void push (const int size, void * value); void pop (const int size, void ** valueptr);

I don't think this will be great in general, but if you write a compiler then it can generate all the correct code, in the same as the C compiler.

Internaly, I will have two versions, one for debugging, which stores the size value, and the other for "performance", which does not. Debug first.



I would give up on the idea of ​​pointers because

  • it uses extra space
  • the allocated space must be managed by something.

If the stack stores values, then after its appearance it is not responsible.

Implementation:

unsigned char space[BIG];
unsigned char *stack = &space[0];
int top = 0;
void push(const int size, void* value) {
    unsigned char* valp = (char *)value;
    *(int *)stack = size;
    stack += sizeof(int);
    for (int i=0; i<size; ++i) {
       *stack++ = *val++;
    }
}

      

pop is the opposite,

+1


source


if i didn't understand what you want, this is a stack where you can put data of any type you need. Here is the idea for "struct any". I think this will help.

union multitype
{
    int     asInt;
    void    *asVPtr;
    TYPE_A  *asA;
    TYPE_B  *asB;
    ...
}

typedef struct _any {
    int              type;
    union multitype  value;
} Any;

void any_put_int(Any *pAny, int value);
void any_put_v_ptr(Any *pAny, void *value);
void any_put_typeA_ptr(Any *pAny, TYPE_A *value);
void any_put_typeB_ptr(Any *pAny, TYPE_B *value);
...

int     any_get_int(Any *pAny);
void*   any_get_v_ptr(Any *pAny);
TYPE_A* any_get_typeA_ptr(Any *pAny);
TYPE_B* any_get_typeB_ptr(Any *pAny);
...

      



If we were to get stacking based on the Any structure, the codes in the question would be like this.

for (int i = 0; i < 20; i++){
    Any anAny;
    any_put_int(&anAny, i);
    stack_push(s, anAny); // or stack_push(s, &anAny);
}

      

+2


source







All Articles