Parameter passing to function with void * as Argument

Earlier I had one structure C

typedef struct c
{
    int cc;
}CS;

I used to call a library function say int GetData(CS *x) which was returning me the above structure C with data.

GetData(CS *x)

Function call used to be like:

CS CSobj;
GetData(&CSObj);

Now there are two structures say C and D

typedef struct c
{
    int cc;
}CS;
CS CSobj;

typedef struct d
{
    int dc;
    int dd;
}DS;
DS DSobj;

Function GetData() has been modified to:

GetData(void* x)

I have to call the library function say int GetData(void* x) which will be returning me one of the above structures through that void* paramter. The return type of the function tells which structure is returned.

Problem is while calling the function GetData() how and what parameter to pass since I am unaware of which struct the function will return. Any way out of this problem?

Without knowing more, a NULL pointer is a good guess.

Regards,
Alister

Passing a pointer to memory location which is big enough to hold the larger of the two structures will solve this problem.
Union will solve this issue.

Yes, a union is useful in this situation. Specifically:

enum { TYPE_CS, TYPE_DS };

typedef struct CS {
        int type;
        int cc;
} CS;

typedef struct DS {
        int type;
        int dc;
        int dd;
} DS;

typedef union S {
        int type;
        DS ds;
        CS cs;
} S;

CS mycs={TYPE_CS, 0};
DS myds={TYPE_DS, 1, 1};

void myfunc(S *data)
{
        switch(s->type) {
        case TYPE_DS:
                s->ds.dc=0;
                s->ds.dd=0;
                break;
        case TYPE_CS:
                s->cs.cc=0;
                break;
        }
}

myfunc(&mycs);
myfunc(&myds);

Your function can tell which is which by checking the value of the type variable, then using either the ds or cs member of the union. All the members of the union overlap.

1 Like

Modifying the myfunc function changing

data->type

inplace of

 s->type 
void myfunc(S *data)
{
        switch(data->type) {
        case TYPE_DS:
                data->ds.dc=0; 
                data->ds.dd=0;
                break;
        case TYPE_CS:
                data->cs.cc=0;
                break;
        }
}
1 Like

Thanks Coronna and Techmonk for the replies.
I guess(may be I am wrong) the func call is incorrect.

myfunc(&mycs);
myfunc(&myds);

We need to pass object of type S.

S sobj = {.type = 1};
myfunc(&sobj);

if(sobj.type == 0)
{
    print sobj.cs.cc
}
else
{
    print sobj.ds.dc; 
    print sobj.ds.dd;
} 

Did you try the code or just consider it to look wrong...?

Why?

The whole point of using a union, and the whole point of adding type to the beginning of your CS and DS structures, was that they'd all have the same memory layout.

The compiler warns you since it doesn't know you built with these assumptions in mind. You can avoid the warning with a typecast if you want:

myfunc((S *)&obj);
1 Like

ok that is fine

CS and DS do not need a type member. Whenever CS and DS are being used directly, the code using them already knows what they are. Only ignorant code inspecting the union needs access to a type flag.

An unrequired additional member needlessly increases storage requirements. The additional member changes the ABI, which could be an issue if backward compatibility is relevant (probably not in this case) and if any instances of these objects have been serialized.

Any structs that may be added to the union in the future will need to adhere to this format.

The redundancy is obvious when you consider that with a type member introducing every struct, you don't need the union at all. You can just cast to int, pass that, check the value, and then cast to either DS or CS. It's not even especially ugly.

void myfunc(int *type)
{
        CS *c;
        DS *d;

        switch(*type) {
        case TYPE_DS:
                d = (DS *) type;
                d->dc=0;
                d->dd=0;
                break;
        case TYPE_CS:
                c = (CS *) type;
                c->cc=0;
                break;
        }
}

myfunc((int *) &mycs);
myfunc((int *) &myds);

Or if you do keep the union, the type member, which is barely more than a decoration, could be eliminated:

typedef union S {
        DS ds;
        CS cs;
} S;

void myfunc(S *data)
{
        switch(data->ds.type) {  /* even if the current member is cs, this is not an error */ 
        case TYPE_DS:
                data->ds.dc=0;
                data->ds.dd=0;
                break;
        case TYPE_CS:
                data->cs.cc=0;
                break;
        }
}

The redundancy which allows for these alternatives is a strong hint that there's a simpler way. I would suggest using a tagged union and leaving the initial structs as they were:

typedef struct US {
        int type;
	union {
		DS ds;
		CS cs;
	} s;
} US;

Regards,
Alister

1 Like

Bad advice! Very dangerous! Unions do not work that way!

If you don't add the 'type' value to the structures, then it won't work properly in the union! It will refer to some other member.

I'm assuming that you misunderstood what I meant by 'tagged union'. It's the final data structure in my previous post, following the text which you quoted. In C, a tagged union is not a union; it is a struct containing a tag (or type) and a union.

Regards,
Alister

I repeat, unions do not work that way.

CS and DS were separate structure members originally. Putting them in a union like you suggest, means they will occupy the same memory! Alter CS and DS will change with it.

Furthermore, you say: "An unrequired additional member needlessly increases storage requirements." And then you suggest a structure that still has the "pointless" type element instead! Perhaps you didn't realize that elements in a union occupy the same place in memory... Meaning the "type" I put in the union wasn't an extra element, it was the same element.

The scheme I suggested is the one I see in use in practice in many libraries. I have never seen anyone use a scheme like yours (probably because it wouldn't work).

It comes down to this:

typedef struct mystr1 {
        int type;
        int payload;
} mystr;


typedef struct mystr2 {
        int type;
        char payload[64];
} mystr2;

typedef union mystr {
        int type;
        mystr1 t1;
        mystr2 t2;
} mystr;

The member labelled in red occupies the same area in memory always. It is not duplicated.

You can repeat it until you're keyboard is dust, but the number of repetitions won't change the fact that you have misunderstood my proposal. Unions aren't complicated and I understand how they work (and structs as well).

Yes, of course. A union is large enough to store its largest member but can only hold one member at a time. If the union consisted of a long int and a float, the same would be true, since their base address would be the same. I understand this. It looks like you do too. This suggests to me that the misunderstanding is not at the C language level, but higher up.

Look at your code (in post #4) where you first suggested the arrangement where both structs and the union include the type int as their first member.

Are you suggesting that mycs.type and myds.type occupy the same memory location? Obviously not. They are different instances of different types. My point regarding pointlessly increasing storage is that neither of those instances needs a type member. Any code that deals with them directly knows what they are.

The only code that needs to discover the type is the code handling a union. Wrap the union in a struct, and only in the struct that wraps the union do you have a member which serves as a type tag. If we were working with thousands of instances of CS/DS or mystr1/mystr2, and only needed one instance of a union to pass to/from functions, then with your approach there would be thousands of pointless type ints consuming storage when only one would be needed.

This statement also suggests that you completely misunderstood my proposal, because tagged unions are conceptually simple and extremely common. Not only do they work well, they are a natural way to express anything which can take on one of several aspects.

Browsing OpenBSD online cvsweb: nawk has a tagged union at the core of the finite automaton which implements its regular expression engine. find uses a tagged union for the core of its planner (which implements the boolean expression of command line primaries). I saw two tagged unions in a sed header, one for sed commands and one for addresses.

To not make an already long post longer than it needs to be, I will only show the simplest case, the tagged union representing sed line addresses:

/*
 * Format of an address
 */
struct s_addr {
        enum e_atype type;                      /* Address type */
        union {
                u_long l;                       /* Line number */
                regex_t *r;                     /* Regular expression */
        } u;
};

The type member tags the union and informs any code that accesses the union which type of address it contains. Neither address data type (u_long and regex_t) needs to carry around its type. For example, any code that works with line number addresses knows that it's dealing with u_long.

Have you actually never seen this type of data structure before, where one of the members is a union and another is the type of the union's current/active member?

Replace the union members in that sed example, u_long and regex_t, with CS and DS and you have exactly what I suggested when I said to leave the original structs unmodified and use a tagged union.

If after reading this post you still believe that I don't understand unions, and if you feel the need to educate me, please take a moment and a breath to consider that it may be you that is missing something, probably not at the C language level, but somewhere else.

Regards,
Alister