Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic data type in C [ void * ] [duplicate]

Tags:

c

Hello I am trying to use void * as a generic data type in C. What I want is a mechanism using which I can store anything and get anything. I wrote some code, but it is failing in the last case. Can anybody please take a look at the code, If you have any other idea please let me know.

I know what I am trying to store, so at that point I know the data type, but during retrial I only know the starting address and size .

Here is the code :

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>


static void store( void *destination, void *source, size_t size ) {
    memcpy ( (char*)destination, source, size);
}
static void retrieve ( void *destination, void *source, size_t size) {
    memcpy ( destination, (char*)source, size);
}

void *storage_char_ptr = (void*) malloc ( sizeof( char* ));
void *storage_int_ptr  = (void*) malloc ( sizeof(int*));
void *storage_int      = (void*) malloc ( sizeof( int));

int main() {

    int int_in = 65;
    void *int_out_ptr;
    int *ptr = ( int*) malloc ( sizeof(int));
    memcpy ( ptr, &int_in, sizeof(int));

    store ( storage_int_ptr, &ptr, sizeof(int*));
    retrieve ( &int_out_ptr, storage_int_ptr, sizeof(int*));
    assert ( int_in == *(int*)int_out_ptr);

    char *char_in = "HelloWorld!!";
    void *char_out;
    store ( storage_char_ptr, &char_in, sizeof(char*));
    retrieve ( &char_out, storage_char_ptr, sizeof(char*));
    assert ( strcmp ( char_in, (char*)char_out ) == 0 );

    char_in = _strdup("HelloWorld!!");
    store ( storage_char_ptr, &char_in, sizeof(char*));
    retrieve ( &char_out, storage_char_ptr, sizeof(char*));
    assert ( strcmp ( char_in, (char*)char_out ) == 0 );

    /* This is where it is failing */
    int_in = 55;
    void* int_out;
    store   ( storage_int, &int_in, sizeof(int));
    retrieve ( &int_out, storage_int, sizeof(int));
    assert  ( 55 == *(int*)int_out);

} 
like image 819
Avinash Avatar asked Apr 05 '11 11:04

Avinash


1 Answers

It's much better to use a union of all types you will need instead of void*, combined with an enumeration of the selected type. If you don't have a finite list of types, then use a struct containing void* pointer and the size allocated at least.

For example:

struct ANYTYPE
{
    enum {
      typUndefined,
      typInt,           // 1
      typUint,
      typString,
      typByteString,
      typLong,          // 5
      typFloat,
      typDouble,
    } iType;

    void* value;
};

This allows you to easily deallocate the memory correctly and make generic code that can analyze the type before acting on the value. You have a similar option with union:

struct ANYTYPE
{
    enum {
      typUndefined,
      typInt,           // 1
      typUint,
      typString,
      typLong
    } iType;

    union
    {
        int i;
        unsigned int u;
        char* s;
        long l;
    } value;
}

In a union, all elements are using same memory space and only one should be accessed. Via the enumeration, you know which element should be accessed. Of course you don't have OO protection like in C++, so you need to be sure you correctly set the enumeration everywhere you use this struct.

like image 102
Benoit Thiery Avatar answered Sep 20 '22 23:09

Benoit Thiery