Parameter passing to function with void * as Argument


 
Thread Tools Search this Thread
Top Forums Programming Parameter passing to function with void * as Argument
# 8  
Old 05-23-2014
Quote:
Originally Posted by Corona688
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:

Code:
myfunc((S *)&obj);

ok that is fine
# 9  
Old 05-23-2014
Quote:
Originally Posted by Corona688
Yes, a union is useful in this situation. Specifically:

Code:
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;

...<snip>...


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.
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.
Code:
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:
Code:
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:
Code:
typedef struct US {
        int type;
	union {
		DS ds;
		CS cs;
	} s;
} US;

Regards,
Alister
This User Gave Thanks to alister For This Post:
# 10  
Old 05-26-2014
Quote:
Originally Posted by alister
I would suggest using a tagged union and leaving the initial structs as they were:
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.
# 11  
Old 05-26-2014
Quote:
Originally Posted by Corona688
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
# 12  
Old 05-26-2014
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:

Code:
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.

Last edited by Corona688; 05-26-2014 at 01:41 PM..
# 13  
Old 05-26-2014
Quote:
Originally Posted by Corona688
I repeat, unions do not work that way.
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).

Quote:
Originally Posted by Corona688
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.
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.

Quote:
Originally Posted by Corona688
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.
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.

Quote:
Originally Posted by Corona688
Code:
CS mycs={TYPE_CS, 0};
DS myds={TYPE_DS, 1, 1};

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.

Quote:
Originally Posted by Corona688
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).
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:
Code:
/*
 * 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
Login or Register to Ask a Question

Previous Thread | Next Thread

10 More Discussions You Might Find Interesting

1. Shell Programming and Scripting

Passing command as a function parameter

Hi All, Just trying to implement the below shell script using AIX ksh shell. myfunc { eval "$*" } CMD='ls -la /etc/hosts | awk '{print $9"|"$5}'' myfunc $CMD Keeping getting "|}: not found" errors, any pointers would greatly be appreciated. Kind Regards Ed Please... (2 Replies)
Discussion started by: eo29
2 Replies

2. Shell Programming and Scripting

Passing parameter to script, and split the parameter

i am passing input parameter 'one_two' to the script , the script output should display the result as below one_1two one_2two one_3two if then echo " Usage : <$0> <DATABASE> " exit 0 else for DB in 1 2 3 do DBname=`$DATABASE | awk -F "_" '{print $1_${DB}_$2}` done fi (5 Replies)
Discussion started by: only4satish
5 Replies

3. Shell Programming and Scripting

passing argument from one function to another

Hi all, In the given script code . I want to pass the maximum value that variable "i" will have in function DivideJobs () to variable $max of function SubmitCondorJob(). Any help? Thanks #!/bin/bash ... (55 Replies)
Discussion started by: nrjrasaxena
55 Replies

4. Shell Programming and Scripting

Passing sql as parameter to unix function

Hi, I have a function which connects to the db and runs the sql. it works fine when I run it like: function "select empname from emp;" but when I try to pass the sql string to a variable which in turn in fed to the function , it throws error. please advise. Thanks, Arnie. (1 Reply)
Discussion started by: itsarnie
1 Replies

5. Shell Programming and Scripting

Passing commandline argument to a function

Hi, I have 2 ksh scripts. Script1.ksh contains function definition. script1.ksh function f1() { while getopts a:c: args do case $args in a) ARG1=$OPTARG ;; c) ARG2=$OPTARG ;; \?) echo "Error no valid Arguments passed" esac done echo $ARG1 echo $ARG2 script2.sh (2 Replies)
Discussion started by: siba.s.nayak
2 Replies

6. Shell Programming and Scripting

Passing more than one argument in a function

Hi All, Calling a function with one argument and storing the return value in a shell script is as below:( so far I know) value="`fun_1 "argument1"`" Its working perfectly for me. Can u help me with passing more than one argument and storing the return value Thnaks in advance JS (1 Reply)
Discussion started by: jisha
1 Replies

7. Programming

How to return void function pointer

Hello all im trying to build function that will return void function pointer what is mean is ( not working ) the main function void * myClass::getFunction(int type){ if(type==1) return &myClass::Test1; if(type==2) return &myClass::Test2; } void myClass::Test1(){... (1 Reply)
Discussion started by: umen
1 Replies

8. UNIX for Advanced & Expert Users

Parameter passing in a function

I need to pass a parameter to a function in a script. My parameter is a string. When I display the parameter within my function, I only get the first word from string I pass in. How can I make the function receive the whole string (and not terminate at the first space it encounters)?. part of... (2 Replies)
Discussion started by: fastgoon
2 Replies

9. Shell Programming and Scripting

Passing a string parameter to a function

I need to pass a parameter to a function in a script. My parameter is a string. When I display the parameter within my function, I only get the first word from string I pass in. How can I make the function receive the whole string (and not terminate at the first space it encounters)?. part of... (1 Reply)
Discussion started by: fastgoon
1 Replies

10. UNIX for Dummies Questions & Answers

Passing Argument to Function

May i know how to pass an argument to a function in a shell script? Sorry, i din stated that it is in a shell script in my previous post. Means: checkStatus() { ........... } read status; I wanna use the status in the function checkstatus, how... (2 Replies)
Discussion started by: AkumaTay
2 Replies
Login or Register to Ask a Question