Generic data type in C [ void * ]

23,407

Solution 1

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.

Solution 2

You are copying the integer value (55) into the pointer int_out. Whatever lies at (the next 4 to 8 bytes at) address 55, it is unlikely to have the numerical value 55. Instead, try

int int_in = 55;
int int_out;
store   ( storage_int, &int_in, sizeof(int));
retrieve ( &int_out, storage_int, sizeof(int));
assert  ( 55 == int_out);

Another problem with your code: in the char_in/char_out parts, you are only ever copying pointer values. This works (in this case), but is not likely what you really intended, or is it? If you really want to store the pointer, you can skip the store and retrieve part:

char* str_in = "hello, world";     // Original value
void* generic_ptr = str_in;        // ... a pointer to which is stored in some data structure
char* str_out = generic_ptr;       // ... which can later be retrieved

will work as well. On the other hand: if you intend to store the actual content of the string, you have to copy it (like, with _strdup as in your second example), and save the pointer to the copy of the string:

char* str_in = _strdup("copy me");
void* generic_ptr = str_in;         // Gets stored in your data structures

Solution 3

You're overwriting the pointer, then dereferencing it... if your code looked like this it would work... but that may not be what you're after.

    int int_out;
    store   ( storage_int, &int_in, sizeof(int));
    retrive ( &int_out, storage_int, sizeof(int));
    assert  ( 55 == int_out);

or:

    int *int_out;
    store   ( storage_int, &int_in, sizeof(int));
    retrive ( &int_out, storage_int, sizeof(int));
    assert  ( 55 == (int)int_out);

However, in the second case this is a bit dubious, because it assumes that both 'int' and 'int*' are the same size, so you're able to store one on top of the other when retrieving. I believe this isn't the case on all systems.

Solution 4

Dirk is totally correct. Another way to express this, is that there is no space allocated to put retrieved data in.

try:

int_in = 55;
void* int_out = malloc (sizeof (int_in));
store   ( storage_int, &int_in, sizeof(int));
retrieve ( int_out, storage_int, sizeof(int));
assert  ( 55 == *(int*)int_out);

Of course, you may want to use something other than malloc(), and there is no check to see if malloc() failed, but this should get you on the right track.

Share:
23,407

Related videos on Youtube

Avinash
Author by

Avinash

Something which i have done. https://github.com/davinash?tab=repositories

Updated on July 09, 2022

Comments

  • Avinash
    Avinash almost 2 years

    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);
    
    } 
    
  • Avinash
    Avinash about 13 years
    @Benoit Thiery, Could you please explain more, any example if you have. I am intrested in struct solution.
  • Avinash
    Avinash about 13 years
    thanks Benoit, But I have finite list of types, So could you please shed more light on struct approach.
  • Prof. Falken
    Prof. Falken about 13 years
    @Avinash, even you have a finite list of types, union is still better. A union is almost the same as a struct.
  • Avinash
    Avinash about 13 years
    but how do i handle structure pointers in this case ?
  • Avinash
    Avinash about 13 years
    I am trying to write a stl vector in C, and I could do it if client allocating memory on the heap and pass as an element to me. But I want it to work with basic datatype and there should not be special way to pass variables on the stack or heap variables there is way to do this using MACROS but i was looking for option which avoid MACROS.
  • Lundin
    Lundin about 13 years
    This is called a "variant". It is not necessarily better than malloc, it is a very memory ineffective way of writing generic data types. There is a reason why so few languages have support for their own variant type.
  • Lundin
    Lundin about 13 years
    @Avinash STL vectors handle dynamic memory allocation internally and make hardcopies of all data. As your code doesn't copy any data, it is rather a kind of lookup table than a container class.
  • Avinash
    Avinash about 13 years
    @Lundin, What does hard copy of all data means. Does it do memcpy internally ???

Related