Passing different object pointer types to the same arg?

This is a discussion on Passing different object pointer types to the same arg? within the C Programming forums, part of the General Programming Boards category; Hello, I have several pointers to structures types which I would like to pass to a function. However, once in ...

  1. #1
    Registered User
    Join Date
    Jun 2010
    Posts
    45

    Passing different object pointer types to the same arg?

    Hello,

    I have several pointers to structures types which I would like to pass to a function. However, once in the function, I need to know the correct pointer to struct type in order to continue the function's code. Please consider the following code:

    Code:
    #include <stdio.h>
    
    typedef struct tag1{
    int a;
    long h;
    }t1;
    
    typedef struct tag2{
    int a;
    int *y;
    }t2;
    
    void f1(void *i)
    {
       t1 *R = (t1*)i;	
       R->a = 9;
    }
    
    int main()
    {
       t1 x;
       t2 y;
       f1(&x);
    }
    Therefore if I call f1 with this line:

    f1(&x);

    everything is okay. But if I call f1 with this line:

    f1(&y);

    Then I have a problem where the member "a" in t2 doesn't get 9 assigned to it.

    What can be done so that which ever type of pointer to struct I decide to pass into the f1 function can be automatically typecasted to the correct pointer to struct type?

    All help appreciated!
    Last edited by see the big C; 06-16-2010 at 04:30 PM.

  2. #2
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    If you're trying to use void pointers, you have to keep track of some way to know what you're allowed to dereference it to. You can't just assume it's a double if you're passing it a character pointer. Likewise, you can't assume it's struct1 when it's really struct2. Add an argument that tells you what you're doing, if you really insist on using void pointers:
    Code:
    void foo( void *v, int t )
    {
        if( t == 1 )
        {
            ...something...
        }
        else
        {
            ...something else...
        }
    }

    Quzah.
    Hope is the first step on the road to disappointment.

  3. #3
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    21,636
    You cannot really do that. One option is to use a function-style macro instead of a function. Another option, if feasible, is to have a function pointer parameter, and then you call the desired function to get the desired value/action. This would be similiar to how say, qsort() makes use of the comparator function pointer that you pass to it.
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  4. #4
    Registered User
    Join Date
    Jun 2010
    Posts
    45
    Hello quzah,

    Thankyou for your response. One thing though, in your sample, if t = 1, I will do something... with... struct1, then another time if t = 2, I will do something else ...with struct2. So like this:

    Code:
    #include <stdio.h>
    
    typedef struct tag1{
    int a;
    long h;
    }t1;
    
    typedef struct tag2{
    int a;
    int *y;
    }t2;
    
    void f1(void *i, int s)
    {
        if(s == 1)
         {
            t1 *X = (t1*)i;	
            X->a = 9;
          }
        else if(s==2)
          {
             t2 *Y = (t2*)i;
             Y->a = 11;
          }
    }
    
    int main()
    {
    t1 x;
    t2 y;
    
    f1(&x,1);
    f1(&y,2);
    }

    In my project, this so called "something" that we do for struct1 is also done identically for struct2 and can be 30 or 40 lines long! Also, to remind ourselves that t can be 1 to perhaps 50 or 100.... therefore, f1() will be very long with alot of if's/else statements containing the the same 50 or 100 lines. Here let me show a sample function in my real code:

    Code:
    void DDLB_retrieve_from_eeprom(                        
    ddlb    *obj_ddlb,  enum eSPI_MEMBANK  Eep_Bank_Num,  		
    unsigned short eeprom_gsoa)    	
    {
    unsigned char   j, k, s, totLists;  
    unsigned char   eeprom_buff[4096];
    unsigned char   eep_Val1 = 0, eep_Val2 = 0;
    
    totLists 	=  obj_ddlb->dc_size;
    ULC_FLASH_SPI_high_speed_read(eeprom_buff, Eep_Bank_Num, 0, 0, 4096);
    
    eep_Val1 = eeprom_buff[eeprom_gsoa];
    eep_Val2 = eeprom_buff[++eeprom_gsoa];
    obj_ddlb->gso_address = API_combine_chars_to_short(eep_Val1, eep_Val2);  
    
    for(j=0; j<totLists; j++)
    {      
      eep_Val1 = eeprom_buff[++eeprom_gsoa];			
      eep_Val2 = eeprom_buff[++eeprom_gsoa];
      obj_ddlb->F__choice[j] = API_combine_chars_to_short(eep_Val1, eep_Val2);  
    
      eep_Val1 = eeprom_buff[++eeprom_gsoa];			
      eep_Val2 = eeprom_buff[++eeprom_gsoa];
    obj_ddlb->F__list_lenght[j] = API_combine_chars_to_short(eep_Val1, eep_Val2);  
    }
    
    for(j=0; j<totLists; j++)
     {
      k = (gsoDdlbx->F__list_lenght[j]);    
      obj_ddlb->E__ll[j] = malloc(k * sizeof(unsigned short));   // freed elsewhere!
                
      for(s=0; s<k; s++)
      {
        eep_Val1 = eeprom_buff[++eeprom_gsoa];
        eep_Val2 = eeprom_buff[++eeprom_gsoa];
        (obj_ddlb->E__ll[j])[s] = API_combine_chars_to_short(eep_Val1, eep_Val2);  
      }
     }
    }
    So as you can see, I would like to have the code above written once in my function while being able to cast the first argument to the appropriate type. Right now I always have to pass in a pointer to a ddlb struct. Hence, I have this function written 5 times in my code.... to acomodate 4 other types. Its very sad! In the future I can end up with 50 types as opposed to the 5 types I have now. If I start embeding the above code in 50 "if/else if" statements.............. I don't know about you, but I just don't like it! Theres got to be a better way!

    laserlight suggested ... function-style macro instead of a function. I wouldn't know exactly how to do this. If someone can direct me to some samples on the Internet... that would be very appreciated. I looked for this myself, but unfortunately I did not find anything that suited my issue.

    Standing by... please do get back.... all help and suggestions are welcome and appreciated! Thanks

  5. #5
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Sounds to me like you didn't design your structures very well.

    Quzah.
    Hope is the first step on the road to disappointment.

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    21,636
    If we examine the places where you dereference obj_ddlb:
    Code:
    obj_ddlb->gso_address = API_combine_chars_to_short(eep_Val1, eep_Val2);
    obj_ddlb->F__choice[j] = API_combine_chars_to_short(eep_Val1, eep_Val2);
    obj_ddlb->F__list_lenght[j] = API_combine_chars_to_short(eep_Val1, eep_Val2);
    obj_ddlb->E__ll[j] = malloc(k * sizeof(unsigned short));
    (obj_ddlb->E__ll[j])[s] = API_combine_chars_to_short(eep_Val1, eep_Val2);
    So, if you use my second suggestion, this means providing getter/setter functions, e.g., one can call:
    Code:
    ddlb_set_F_choice(obj_ddlb, j, API_combine_chars_to_short(eep_Val1, eep_Val2));
    A generic retrieve_from_eeprom function would then be able to call this function when it is passed as a function pointer argument.

    If you prefer to use a function-style macro, then just search the Web for tutorials on C macros. After you have a basic understanding of how they work, you would be able to write a RETRIEVE_FROM_EEPROM macro that wraps its body in a do while (0) loop, allowing you to declare the "local" variables that you need.
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    Registered User
    Join Date
    Jun 2010
    Posts
    45
    Hello laserlight,

    I have seen C macros samples in books ...here and there... and on the net.... like this:

    Code:
    #define SET_LINKS(p) do { \
            (p)->next_task = &init_task; \
            (p)->prev_task = init_task.prev_task; \
            init_task.prev_task->next_task = (p); \
            init_task.prev_task = (p); \
            (p)->p_ysptr = NULL; \
            if (((p)->p_osptr = (p)->p_pptr->p_cptr) != NULL) \
                    (p)->p_osptr->p_ysptr = p; \
            (p)->p_pptr->p_cptr = p; \
            } while (0)
    and here:

    Introduction to Macros in C | Bukisa.com

    But excuse my ignorance, I haven't been programming that long which leads me to say that I don't see how the above #define macro can solve my *original* post in this thread.

    I like your proposition... as you said:

    >you would be able to write a RETRIEVE_FROM_EEPROM macro that wraps its body >in a do while (0) loop, allowing you to declare the "local" variables that you need.

    But I just wouldn't know where to start, confused!

    Then, in reference to my innitial post (see below), how would I write the f1() macro that wraps its body in a do while (0) loop, allowing me to declare the "local" variables that I need.....<<<< I never did this before! I would like to learn please.
    :-)

    If we take my original code sample, based on your #define proposition where would the #define statement go and what would it contain... :

    Code:
    #include <stdio.h>
    
    typedef struct tag1{
    int a;
    long h;
    }t1;
    
    typedef struct tag2{
    int a;
    int *y;
    }t2;
    
    void f1(void *i)
    {
    //   t1 *R = (t1*)i;	
    //  R->a = 9;
    
    // Can you please provide some code to get me started.... 
    
    }
    
    int main()
    {
       t1 x;
       t2 y;
       f1(&x);
       f1(&y);
    }
    Thanks for your kind help.
    Bobby

  8. #8
    Registered User
    Join Date
    Jun 2010
    Posts
    45
    Hello quzah,

    Very possible. I could factor out the common struct members and create a new struct and use a pointer of this struct type and pass that to my function... if that makes any sence to you he he.... I also like laserlight's suggestion about the C macro..... It would give me a chance to start refactoring my code in a small way. Its too late for me to start redesigning / changing member structure data... there's just too many other things to do.

    But hey! thanks for your insignt anyways!

    Bobby
    Last edited by see the big C; 06-16-2010 at 06:29 PM.

  9. #9
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    21,636
    Quote Originally Posted by see the big C
    But excuse my ignorance, I haven't been programming that long which leads me to say that I don't see how the above #define macro can solve my *original* post in this thread.
    It would solve it if all that you are doing right now is to copy and paste the function verbatim, changing the function name, the type (and possibly the name) of the obj_ddlb parameter, but with everything else exactly the same.
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  10. #10
    Registered User
    Join Date
    Jun 2010
    Posts
    45
    >It would solve it if all that you are doing right now is to copy and paste the >function verbatim, changing the function name, the type (and possibly the name) >of the obj_ddlb parameter, but with everything else exactly the same.

    confused! Help... I need a sample!

    Lets use the *original* post: this one:

    Code:
    #include <stdio.h>
    
    typedef struct tag1{
    int a;
    long h;
    }t1;
    
    typedef struct tag2{
    int a;
    int *y;
    }t2;
    
    void f1(void *i)
    {
    //   t1 *R = (t1*)i;	
    //  R->a = 9;
    
    // Can you please provide some code to get me started.... 
    
    }
    
    int main()
    {
       t1 x;
       t2 y;
       f1(&x);
       f1(&y);
    }
    - So I have to change the function name... so I have to change f1()'s name????
    - the type ????
    - (and possibly the name) >of the obj_ddlb parameter

    I don't get it... I need a small sample... I am completely lost... confused I don't see what you mean.... can someone elaborate on what I should be doing. discouraged!

  11. #11
    Registered User
    Join Date
    May 2010
    Location
    Naypyidaw
    Posts
    1,314
    Code:
    typedef struct common {
       int a;
       double foo;
    }common;
    typedef struct {
       common com;
       int *y;
    } t1;
    
    typedef struct {
       common com;
       long int h;
    } t2;
    
    void f(void *p)   // pass t1 or t2 pointer
    {
       common *cp = p;
       cp->a = 9;
       cp->foo = 3.43;
    }
    int main(void)
    {
       t1 x;
       t2 y;
       f(&x);
       f(&y);
       printf("%d %g\n",x.com.a,x.com.foo);
       printf("%d  %g\n",y.com.a,y.com.foo);
       return 0;
    }
    Put all common members in struct and make it the first member.

  12. #12
    Registered User
    Join Date
    Jun 2010
    Posts
    45
    Thanks Bayint Naung!

    1) Is it obligatory to make it the first member?
    2) Is it possible to do all of this without using an extra common structure? Perhaps by a #define macro or something like that... just asking!

    Thankyou for listening to my "I need a small sample" plead.

    I appreciate your straight forwards help!

    Regards
    Bobby

  13. #13
    C++まいる!Cをこわせ! Elysia's Avatar
    Join Date
    Oct 2007
    Posts
    22,546
    1) In this example, yes. That means all the variables in common would end up first in the struct, so it can be "thought" of a common type struct where all the other variables after common have been cut off.
    You could put the common struct further down, but then you would have to add an offset in your code when converting to a common pointer, which is obviously more work and error prone.
    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.

  14. #14
    Registered User
    Join Date
    May 2010
    Location
    Naypyidaw
    Posts
    1,314
    I don't know how you could access the common struct if it's put further down.
    since offsetof() needs struct type.
    Having common struct as first member is definitely easier.
    1) Is it obligatory to make it the first member?
    Yes, because standard grantees that there'll be no padding in front of first member.
    i.e
    Code:
        t1 x;
        t2 y;
        &x == &(x.com) 
        &y == &(y.com)
    2) Is it possible to do all of this without using an extra common structure? Perhaps by a #define macro or something like that... just asking!
    No /* comment */

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 5
    Last Post: 04-04-2009, 03:45 AM
  2. Ban pointers or references on classes?
    By Elysia in forum C++ Programming
    Replies: 89
    Last Post: 10-30-2007, 03:20 AM
  3. circular doubly linked list help
    By gunnerz in forum C++ Programming
    Replies: 5
    Last Post: 04-28-2007, 08:38 PM
  4. Passing a pointer as a reference
    By hYph3n in forum C++ Programming
    Replies: 5
    Last Post: 10-04-2006, 01:45 PM
  5. Direct3D problem
    By cboard_member in forum Game Programming
    Replies: 10
    Last Post: 04-09-2006, 03:36 AM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21