Thread: help needed with void pointers.

  1. #1
    Registered User
    Join Date
    Apr 2008
    Posts
    87

    help needed with void pointers.

    Hi, I'm trying to create a generic link list. Here's the data structure for node:
    Code:
    typedef struct node_s
    { 
       void *data;
       struct node_s *next;
    }node;
    Now let's say I want the data pointer to point to a vector structre:

    Code:
    typedef struct
    {
      double coord[3];
    }vector;

    I can assign data (of some random node in list) address of some vector:

    Code:
    p->data = &v
    p is pointer to node in link list and v is the vector.

    But when I try an operation like this for eg:

    Code:
      p->data->coord[0]  < p->data->coord[1]
    It gives me an error. Is there any way I can solve this ?

  2. #2
    Deathray Engineer MacGyver's Avatar
    Join Date
    Mar 2007
    Posts
    3,210
    You have to cast the void * back to another pointer type before you can dereference it.

  3. #3
    Registered User
    Join Date
    Apr 2008
    Posts
    87
    Quote Originally Posted by MacGyver View Post
    You have to cast the void * back to another pointer type before you can dereference it.
    This
    Code:
     vector *a = (vector *) p->ptr;
     vector *b  = (vector *) p->ptr;
    
    a->coord[0] < b->coord[0]
    did the trick. Is this what you are trying to say ?

  4. #4
    Deathray Engineer MacGyver's Avatar
    Join Date
    Mar 2007
    Posts
    3,210
    Yes.

  5. #5
    Registered User
    Join Date
    Apr 2008
    Posts
    87
    Quote Originally Posted by MacGyver View Post
    You have to cast the void * back to another pointer type before you can dereference it.
    Ok is there any way I can let a function know about the type to which void must be casted to ?
    I wanted to make the program as general as possible.

  6. #6
    Deathray Engineer MacGyver's Avatar
    Join Date
    Mar 2007
    Posts
    3,210
    No, not really just in and of itself. In C++, you could use templates, but that's a different subject.

    What you need to do is separate your linked list implementation from the rest of your program. For example, you could write your linked list implementation in one .c file with all necessary information (ie. the structs, variables, typedefs, etc. etc..) all in the corresponding .h file. Then when you need to use your linked list in a program, you simply include the .h file and compile both .c files.

    What this does is separate this type of information. The linked list doesn't need to know or care about the data that it manages. As far as it is concerned, it's simply pointing to objects of any type, and it really doesn't care about that information. Your program, however, doesn't need to know about the implementation of your linked list. It just needs a way to reference the list and an ability to add, remove, and otherwise manage the elements. It knows what type the elements are, and it doesn't need to care much about anything else.

    If you absolutely need to include meta data, it should be included inside of a struct. The struct should contain an int or enum of sorts that tells you what type of element is being pointed to. In this way, yes, you can have functions know how to cast to what, but in a somewhat limited manner. This depends upon your program and your linked list. If you go this route, you can end up either limiting yourself or overcomplicating the program. Overall, it depends upon what you're trying to do.

  7. #7
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    You can make a function that has a parameter for the type. Then for assigning things to the list:
    Code:
    #define TYPE v
    
    void svdata(node *node, void *p, int type)
    {
         vector *v; int *i; double *d;
         switch(type) {
         case 'v':
                  v = (vector *)p;
                  node->data = v;
                  ....
         case 'd':
              ......
    }
    
    now:
    next(node, my_vector, TYPE)
    If you want to make a linked list for multiple types then each node has to include the type.

    You could always make a struct that has a lot of pointers instead of void. Assign everything NULL so you can check which data is used. If you don't need a high efficiency then you indeed have a multiple type linked list. With some limitations

  8. #8
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Note that this kinda defies the language, which is about fast and efficient code.
    This approach would be faster in C++ due to templates.
    I would try to abstract away the need for the type to the point where the application knows the type, as MacGyver seems to suggest.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  9. #9
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    Well, generally you cannot make a generic list in C. There is no way without having some cost in efficiency, I believe.

    I believe what I proposed is the most efficient in matter of speed. The downside is that you will have to use functions for a lot of things. Like even printing the data, since you don't know for example if it a float or an int. But that isn't hard, and the functions with the lot of if's can be stored in another file, so you won't have that long code.

    The problem is if you wanted a linked list with multiple types, which isn't supported even by some languages that have real polymorphism (like Haskell). Then you will need to add as McGyver said another int or enum on the node and again have functions read it.

  10. #10
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by C_ntua View Post
    I believe what I proposed is the most efficient in matter of speed. The downside is that you will have to use functions for a lot of things. Like even printing the data, since you don't know for example if it a float or an int. But that isn't hard, and the functions with the lot of if's can be stored in another file, so you won't have that long code.
    It does not cause such a big speed impact, true (but it could be removed altogether), but it does cause code bloating (duplicate code everywhere), which is why such an approach is generally not recommended.
    It's prone to bugs, errors and it's a pain to implement the scheme everywhere.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  11. #11
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    If you didn't want to have a bad-pseudo-polymorphism then you would have to make a node for every data type you use. That will also need more code. Then you will have functions for every type. You would probably copy-paste a lot of things and get again bugs and lose time.

    What McGyver suggested as an idea is better. But practically it might be worse. Your program will know what data types it uses. But what if you want to change the main program? You will have to change everything that has to do with types (though you could find-replace easily). And it would have more code, since it will have all the castings.

    Having the casting and type decision in separate functions would make the main program more readable. For example:

    Example:
    Code:
    #define T1 long double
    #define T2 int
    #define ....
    
    if (strcmp("T1", float) == 0)
       printf("&#37;f", i);
    else (strcmp("T1", int) == 0)
       printf("%d", i);
    
    etc etc
    
    then the same for T2, probably for T3
    You would make a function anyway to printf what you want. So why not do everything you want in the function and save code from the main program?
    Though, everything depends on what you want

    If you didn't then you would have to change everything in the main program. Bugs...

  12. #12
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    In C, a linked list that deals with nothing but void pointers *is* a generic list. The language just isn't well suited for imparting meaningful type information within the list abstract data type. Which is why pushing out type-related responsibilities to the user of the list makes sense. Which really means that each user of the list simply casts to the type of object that was originally inserted.

    Now you have a single copy of the list code - multiple users of the list (even within the same compilation unit) - and no additional overhead.

    >> though you could find-replace easily
    Changing a single typedef is even easier

    gg

  13. #13
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    Well, you are focusing more on making a "library" that will be useful for everyone and everything. I am more considered on having a main program + libraries that everyone will use. So you wouldn't want to change a lot the main program. Just add maybe something. Or change the datatypes and some line of code.

    That's why I said it depends. If you want a library with a linked list that is functional and useful then you just leave the user to do the casting. If you want though a main program that does something to a linked list with a certain datatype, when the datatype can be changed, it is safer and more appropriate to make sure with a function that you will get the desired result. Depending on the user to change the printf()s and the casting isn't I believe the best solution. What if he forgets something? In C that means a big error because the program might run nicely with mixed casting. With a function you would change only the functions parameter (a simple replace).

    Void is polymorphic but incomplete in a way. It lets you assign a value not use it though without casting it. You can make all sort of mistakes. Have the void pointer point at a long double. Change it to point to a character. Forget to change a casting so something is casted to long double. It pointed to 1byte and now you will read 12bytes. Lots and lots of bad things.
    In Java for example a "pointer" to an Object is like void in a way. You can point at any object. But when you cast it to what you want I assume you are safe, because the thing you are pointing at will have to have the appropriate type or the compiler can find the mistake. In C such a thing won't be checked, since C has a different logic.

  14. #14
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    The solution to all of these problems is just to use C++. If you can, of course.
    However, otherwise I must agree with Codeplug.
    Storing runtime information about an object is just not desirable.
    And I would not call void* a polymorphic type, even incomplete. Let's face it. C does not support polymorphism out of the box. You'll have to emulate it.
    In Java, it's safe, because all object are of type Object (if I'm right, I don't know Java), thus it is safe to manipulate all these types via Object*, but such would not be possible in C, and void* is therefore unsafe and not the least polymorphic, and best avoided.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  15. #15
    The larch
    Join Date
    May 2006
    Posts
    3,573
    They say that templates in C++ are (partly) meant to replace macros.

    So I guess it might be possible to do something along these lines:
    Code:
    #define DEFINE_LIST(type) \
    typedef struct type##_node \
    { \
        type data; \
        struct type##_node* next; \
    } type##_node; \
    typedef struct type##_list \
    { \  
        type##_node* head; \
    } type##_list
    
    DEFINE_LIST(int); //defines struct int_list
    If I'm not mistaken something of the kind might be used for generic containers in wxWidgets since it started before templates(?) (although their use is deprecated)
    Last edited by anon; 07-01-2008 at 12:03 PM.
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Inserting a swf file in a windows application
    By face_master in forum Windows Programming
    Replies: 12
    Last Post: 05-03-2009, 11:29 AM
  2. need help with handelling multiple source files
    By DarkMortar in forum C++ Programming
    Replies: 38
    Last Post: 05-26-2006, 10:46 PM
  3. Quack! It doesn't work! >.<
    By *Michelle* in forum C++ Programming
    Replies: 8
    Last Post: 03-02-2003, 12:26 AM
  4. oh me oh my hash maps up the wazoo
    By DarkDays in forum C++ Programming
    Replies: 5
    Last Post: 11-30-2001, 12:54 PM