Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Union and pointer casts?

Reply
Thread Tools

Union and pointer casts?

 
 
Jef Driesen
Guest
Posts: n/a
 
      02-24-2011
Hi,

Suppose I have two distinct data structures:

typedef struct foo_t {
...
} foo_t;

typedef struct bar_t {
...
} bar_t;

and a function that receives a pointer to such a structure, together with a type
to indicate which structure is being passed:

typedef enum data_type_t {
DATA_TYPE_FOO,
DATA_TYPE_BAR
} data_type_t;

void myfunction (data_type_t type, void *data)
{
foo_t *foo = data;
foo_t *bar = data;

switch (type) {
case DATA_TYPE_FOO:
/* Use foo here */
break:
case DATA_TYPE_BAR:
/* Use bar here */
break:
default:
return;
}
}

A typical usage would be like this:

int main(void)
{
foo_t foo;
bar_t bar;

myfunction (DATA_TYPE_FOO, &foo);
myfunction (DATA_TYPE_BAR, &bar);

return 0;
}

Is it portable to replace the separate variables and explicit casts with a union?

typedef union foobar_t {
bar_t bar;
foo_t foo;
} foobar_t;

void myfunction (data_type_t type, void *data)
{
foobar_t *foobar = data;

switch (type) {
case DATA_TYPE_FOO:
/* Use foobar->foo here */
break:
case DATA_TYPE_BAR:
/* Use foobar->bar here */
break:
default:
return;
}
}

I think this is a portable construct, but I'm not 100% sure. Note that it's not
my intent to try to interpret a foo_t as a bar_t. The main purpose of the union
is to improve the readability of the code (my real code has many more foo and
bar structs).

Jef
 
Reply With Quote
 
 
 
 
Joel C. Salomon
Guest
Posts: n/a
 
      02-24-2011
Jef Driesen <(E-Mail Removed)> wrote:
> Suppose I have two distinct data structures:

<snip>
> and a function that receives a pointer to such a structure, together with a type to indicate which structure is being passed:

<snip>
> Is it portable to replace the separate variables and explicit casts with a union?


That is the main use of unions. You might consider this pattern, called a “tagged union”:

struct foo {…};
struct bar {…};

struct foobar {
enum {
T_FOO,
T_BAR,
} tag;
union {
struct foo foo;
struct bar bar;
} data;
};

void myfunction(struct foobar *foobar) {
switch(foobar->type) {
case T_FOO:
/* use foobar->data->foo here */
break;
case T_BAR:
/* use foobar->data->bar here */
break;
default:
fprintf(stderr, "bad type\n");
abort();
}

There are extensions to C (MSVC, Plan 9, gcc with -fms-extensions) that allow
you to not name the union and to refer to foobar->foo or foobar->bar directly;
a version of this will be in the C1x standard.

(Plan 9’s compiler also allowed

typedef struct foo {int bas} foo;
typedef struct bar {int quux} foo;

struct foobar {
foo;
bar;
};

void func(struct foobar f) {
assert(f.bas == f.quux);
}

i.e., using the typedef name to declare an anonymous structure. The current
C1x draft allows that, but N1549 makes clear that this was *not* intended, &
will be removed. Shame, that; it’s a cool & useful feature.)

—Joel

N1549: <http://open-std.org/jtc1/sc22/wg14/www/docs/n1549.pdf>

 
Reply With Quote
 
 
 
 
Tim Rentsch
Guest
Posts: n/a
 
      02-24-2011
Jef Driesen <(E-Mail Removed)> writes:

> Hi,
>
> Suppose I have two distinct data structures:
>
> typedef struct foo_t {
> ...
> } foo_t;
>
> typedef struct bar_t {
> ...
> } bar_t;
>
> and a function that receives a pointer to such a structure, together
> with a type to indicate which structure is being passed:
>
> typedef enum data_type_t {
> DATA_TYPE_FOO,
> DATA_TYPE_BAR
> } data_type_t;
>
> void myfunction (data_type_t type, void *data)
> {
> foo_t *foo = data;
> foo_t *bar = data;
>
> switch (type) {
> case DATA_TYPE_FOO:
> /* Use foo here */
> break:
> case DATA_TYPE_BAR:
> /* Use bar here */
> break:
> default:
> return;
> }
> }
>
> A typical usage would be like this:
>
> int main(void)
> {
> foo_t foo;
> bar_t bar;
>
> myfunction (DATA_TYPE_FOO, &foo);
> myfunction (DATA_TYPE_BAR, &bar);
>
> return 0;
> }
>
> Is it portable to replace the separate variables and explicit casts with a union?
>
> typedef union foobar_t {
> bar_t bar;
> foo_t foo;
> } foobar_t;
>
> void myfunction (data_type_t type, void *data)
> {
> foobar_t *foobar = data;
>
> switch (type) {
> case DATA_TYPE_FOO:
> /* Use foobar->foo here */
> break:
> case DATA_TYPE_BAR:
> /* Use foobar->bar here */
> break:
> default:
> return;
> }
> }
>
> I think this is a portable construct, but I'm not 100% sure. Note that
> it's not my intent to try to interpret a foo_t as a bar_t. The main
> purpose of the union is to improve the readability of the code (my
> real code has many more foo and bar structs).


If called from your example main() function above, technically
this last function crosses over into undefined behavior. In
fact the undefined behavior happens even before getting to
the switch() statement.

To see why this is true, remember what we did: we took a
pointer to a foo_t or bar_t, and converted that to a 'void *'.
Okay, nothing wrong with that. But then, in the revised
myfunction(), we took the 'void *' pointer value and converted
it to a pointer to a foobar_t (the union type). The union type
may have (ie, the Standard allows it to have) a more restrictive
alignment requirement than the struct types. Hence, upon doing
the conversion of a struct pointer (in the guise of a 'void *',
but still pointing to one of the structs), we could get a pointer
that is not correctly aligned for access to the union type. The
Standard says clearly that if the resulting pointer value is not
correctly aligned for the target type then the behavior is
undefined.

If I had to take a bet at even money on this, I would bet that
this code would actually work on a platform chosen at random.
But, if what you're looking for is code that is within the bounds
of the Standard requires to work portably, this approach isn't it.
 
Reply With Quote
 
Jef Driesen
Guest
Posts: n/a
 
      02-24-2011
On 24/02/11 22:02, Joel C. Salomon wrote:
> Jef Driesen<(E-Mail Removed)> wrote:
>> Suppose I have two distinct data structures:

> <snip>
>> and a function that receives a pointer to such a structure, together with a type to indicate which structure is being passed:

> <snip>
>> Is it portable to replace the separate variables and explicit casts with a union?

>
> That is the main use of unions. You might consider this pattern, called a tagged union:
>
> struct foo {};
> struct bar {};
>
> struct foobar {
> enum {
> T_FOO,
> T_BAR,
> } tag;
> union {
> struct foo foo;
> struct bar bar;
> } data;
> };
>
> void myfunction(struct foobar *foobar) {
> switch(foobar->type) {
> case T_FOO:
> /* use foobar->data->foo here */
> break;
> case T_BAR:
> /* use foobar->data->bar here */
> break;
> default:
> fprintf(stderr, "bad type\n");
> abort();
> }


This is something I don't want to do, because the foo and bar data types are
part of a library where I want to be able to add new data types without breaking
backwards compatibility. But adding new structs to the union may change its size
and hence break backwards compatibility.

If the union is not part of the public api and used only internally, that's not
an issue. The union would just be a convenient way to avoid doing explicit casts.
 
Reply With Quote
 
Paul N
Guest
Posts: n/a
 
      02-24-2011
On Feb 24, 8:14*pm, Jef Driesen <(E-Mail Removed)>
wrote:
> Hi,
>
> Suppose I have two distinct data structures:
>
> typedef struct foo_t {
> * * ...
>
> } foo_t;
>
> typedef struct bar_t {
> * * ...
>
> } bar_t;
>
> and a function that receives a pointer to such a structure, together witha type
> to indicate which structure is being passed:
>
> typedef enum data_type_t {
> * * DATA_TYPE_FOO,
> * * DATA_TYPE_BAR
>
> } data_type_t;
>
> void myfunction (data_type_t type, void *data)
> {
> * * foo_t *foo = data;
> * * foo_t *bar = data;
>
> * * switch (type) {
> * * case DATA_TYPE_FOO:
> * * * */* Use foo here */
> * * * *break:
> * * case DATA_TYPE_BAR:
> * * * */* Use bar here */
> * * * *break:
> * * default:
> * * * *return;
> * * }
>
> }
>
> A typical usage would be like this:
>
> int main(void)
> {
> * * foo_t foo;
> * * bar_t bar;
>
> * * myfunction (DATA_TYPE_FOO, &foo);
> * * myfunction (DATA_TYPE_BAR, &bar);
>
> * * return 0;
>
> }
>
> Is it portable to replace the separate variables and explicit casts with a union?
>
> typedef union foobar_t {
> * * bar_t bar;
> * * foo_t foo;
>
> } foobar_t;
>
> void myfunction (data_type_t type, void *data)
> {
> * * foobar_t *foobar = data;
>
> * * switch (type) {
> * * case DATA_TYPE_FOO:
> * * * */* Use foobar->foo here */
> * * * *break:
> * * case DATA_TYPE_BAR:
> * * * */* Use foobar->bar here */
> * * * *break:
> * * default:
> * * * *return;
> * * }
>
> }
>
> I think this is a portable construct, but I'm not 100% sure. Note that it's not
> my intent to try to interpret a foo_t as a bar_t. The main purpose of theunion
> is to improve the readability of the code (my real code has many more fooand
> bar structs).


As an alternative suggestion, why not have a union consisting of a
foo_t * and a bar_t * ?

 
Reply With Quote
 
Ben Bacarisse
Guest
Posts: n/a
 
      02-24-2011
Jonathan Leffler <(E-Mail Removed)> writes:

> On 2/24/11 12:14 PM, Jef Driesen wrote:
>> Suppose I have two distinct data structures:
>>
>> typedef struct foo_t {
>> ...
>> } foo_t;
>>
>> typedef struct bar_t {
>> ...
>> } bar_t;
>>
>> and a function that receives a pointer to such a structure, together
>> with a type to indicate which structure is being passed:
>>
>> typedef enum data_type_t {
>> DATA_TYPE_FOO,
>> DATA_TYPE_BAR
>> } data_type_t;
>>
>> void myfunction (data_type_t type, void *data)
>> {
>> foo_t *foo = data;
>> foo_t *bar = data;
>>
>> switch (type) {
>> case DATA_TYPE_FOO:
>> /* Use foo here */
>> break:
>> case DATA_TYPE_BAR:
>> /* Use bar here */
>> break:
>> default:
>> return;
>> }
>> }
>>
>> A typical usage would be like this:
>>
>> int main(void)
>> {
>> foo_t foo;
>> bar_t bar;
>>
>> myfunction (DATA_TYPE_FOO, &foo);
>> myfunction (DATA_TYPE_BAR, &bar);
>>
>> return 0;
>> }
>>
>> Is it portable to replace the separate variables and explicit casts with
>> a union?


Your code probably does have explicit casts but they've gone from the
example you posted.

>>
>> typedef union foobar_t {
>> bar_t bar;
>> foo_t foo;
>> } foobar_t;
>>
>> void myfunction (data_type_t type, void *data)
>> {
>> foobar_t *foobar = data;
>>
>> switch (type) {
>> case DATA_TYPE_FOO:
>> /* Use foobar->foo here */
>> break:
>> case DATA_TYPE_BAR:
>> /* Use foobar->bar here */
>> break:
>> default:
>> return;
>> }
>> }
>>
>> I think this is a portable construct, but I'm not 100% sure. Note that
>> it's not my intent to try to interpret a foo_t as a bar_t. The main
>> purpose of the union is to improve the readability of the code (my real
>> code has many more foo and bar structs).

>
> I believe it would be portable. You could reasonably change the second
> parameter of myfunction() to a 'foobar_t *', of course.


But that would require a whole lot more casts. The program has no data
that is actually of the union type (it's a figment designed to simplify
the code) so the conversion from the struct pointer to the union pointer
will require a cast (though it may be simply a cast to void *).

To the OP: Have you considered function pointers? Your myfunction
function would reduce to

dispatch[type](data);

and each of functions in the dispatch table would look like this:

void myfunction_foo(void *data)
{
foo_t *foo = data;
/* whatever the switch case did */
}

It means writing a function per case, but there is not that much more
noise in the functions than there is in the switch statement.

--
Ben.
 
Reply With Quote
 
Jef Driesen
Guest
Posts: n/a
 
      02-25-2011
On 24/02/11 22:02, Tim Rentsch wrote:
> Jef Driesen<(E-Mail Removed)> writes:
>
>> Hi,
>>
>> Suppose I have two distinct data structures:
>>
>> typedef struct foo_t {
>> ...
>> } foo_t;
>>
>> typedef struct bar_t {
>> ...
>> } bar_t;
>>
>> and a function that receives a pointer to such a structure, together
>> with a type to indicate which structure is being passed:
>>
>> typedef enum data_type_t {
>> DATA_TYPE_FOO,
>> DATA_TYPE_BAR
>> } data_type_t;
>>
>> void myfunction (data_type_t type, void *data)
>> {
>> foo_t *foo = data;
>> foo_t *bar = data;
>>
>> switch (type) {
>> case DATA_TYPE_FOO:
>> /* Use foo here */
>> break:
>> case DATA_TYPE_BAR:
>> /* Use bar here */
>> break:
>> default:
>> return;
>> }
>> }
>>
>> A typical usage would be like this:
>>
>> int main(void)
>> {
>> foo_t foo;
>> bar_t bar;
>>
>> myfunction (DATA_TYPE_FOO,&foo);
>> myfunction (DATA_TYPE_BAR,&bar);
>>
>> return 0;
>> }
>>
>> Is it portable to replace the separate variables and explicit casts with a union?
>>
>> typedef union foobar_t {
>> bar_t bar;
>> foo_t foo;
>> } foobar_t;
>>
>> void myfunction (data_type_t type, void *data)
>> {
>> foobar_t *foobar = data;
>>
>> switch (type) {
>> case DATA_TYPE_FOO:
>> /* Use foobar->foo here */
>> break:
>> case DATA_TYPE_BAR:
>> /* Use foobar->bar here */
>> break:
>> default:
>> return;
>> }
>> }
>>
>> I think this is a portable construct, but I'm not 100% sure. Note that
>> it's not my intent to try to interpret a foo_t as a bar_t. The main
>> purpose of the union is to improve the readability of the code (my
>> real code has many more foo and bar structs).

>
> If called from your example main() function above, technically
> this last function crosses over into undefined behavior. In
> fact the undefined behavior happens even before getting to
> the switch() statement.
>
> To see why this is true, remember what we did: we took a
> pointer to a foo_t or bar_t, and converted that to a 'void *'.
> Okay, nothing wrong with that. But then, in the revised
> myfunction(), we took the 'void *' pointer value and converted
> it to a pointer to a foobar_t (the union type). The union type
> may have (ie, the Standard allows it to have) a more restrictive
> alignment requirement than the struct types. Hence, upon doing
> the conversion of a struct pointer (in the guise of a 'void *',
> but still pointing to one of the structs), we could get a pointer
> that is not correctly aligned for access to the union type. The
> Standard says clearly that if the resulting pointer value is not
> correctly aligned for the target type then the behavior is
> undefined.


If this is indeed a potential problem, then why doesn't the same logic apply to
my first example too? Here I did cast the data pointer to all possible struct
types, while only one of them will be the correct one:

foo_t *foo = data;
bar_t *bar = data;

Assuming the real type was of type foo_t, the bar variable may now point to a
struct which may have different alignment requirements. Or am I seeing this wrong?

I suppose the correct way would be to cast only to the correct type:

void myfunction (data_type_t type, void *data)
{
foo_t *foo = NULL;
bar_t *bar = NULL;

switch (type) {
case DATA_TYPE_FOO:
foo = data;
/* Use foo here */
break:
case DATA_TYPE_BAR:
foo = data;
/* Use bar here */
break:
default:
return;
}
}

or get rid of the foo and bar variables and cast the data pointer everywhere
where it is accessed:

((foo_t *) data)->member

But this is ugly and error-prone, especially when you have to do this cast often.

> If I had to take a bet at even money on this, I would bet that
> this code would actually work on a platform chosen at random.
> But, if what you're looking for is code that is within the bounds
> of the Standard requires to work portably, this approach isn't it.


I prefer portable code, but I don't want to take it to the extreme either.
 
Reply With Quote
 
Ben Bacarisse
Guest
Posts: n/a
 
      02-25-2011
Jef Driesen <(E-Mail Removed)> writes:
> On 24/02/11 22:02, Tim Rentsch wrote:

<snip>
>> To see why this is true, remember what we did: we took a
>> pointer to a foo_t or bar_t, and converted that to a 'void *'.
>> Okay, nothing wrong with that. But then, in the revised
>> myfunction(), we took the 'void *' pointer value and converted
>> it to a pointer to a foobar_t (the union type). The union type
>> may have (ie, the Standard allows it to have) a more restrictive
>> alignment requirement than the struct types. Hence, upon doing
>> the conversion of a struct pointer (in the guise of a 'void *',
>> but still pointing to one of the structs), we could get a pointer
>> that is not correctly aligned for access to the union type. The
>> Standard says clearly that if the resulting pointer value is not
>> correctly aligned for the target type then the behavior is
>> undefined.

>
> If this is indeed a potential problem, then why doesn't the same logic
> apply to my first example too?


The key information is in the text I've left quoted: union types may
require stricter alignment than pointer types. All pointers to
structure types have the same alignment requirements as do all pointers
to union types, but they don't have the same alignment requirements as
each other.

I agree with what Tim says (in a part I snipped) that it is a reasonable
bet that this will work but it is not guaranteed.

> possible struct types, while only one of them will be the correct one:
>
> foo_t *foo = data;
> bar_t *bar = data;
>
> Assuming the real type was of type foo_t, the bar variable may now
> point to a struct which may have different alignment requirements. Or
> am I seeing this wrong?
>
> I suppose the correct way would be to cast only to the correct type:
>
> void myfunction (data_type_t type, void *data)
> {
> foo_t *foo = NULL;
> bar_t *bar = NULL;
>
> switch (type) {
> case DATA_TYPE_FOO:
> foo = data;
> /* Use foo here */
> break:
> case DATA_TYPE_BAR:
> foo = data;
> /* Use bar here */
> break:
> default:
> return;
> }
> }
>
> or get rid of the foo and bar variables and cast the data pointer
> everywhere where it is accessed:


What you originally has was fine because you can cover the void * to any
structure type without undefined behaviour (they all have the same
alignment requirements after all) provided that you don't access the
"wrong" structure, and your original code ensured that that did not
happen.

> ((foo_t *) data)->member
>
> But this is ugly and error-prone, especially when you have to do this
> cast often.
>
>> If I had to take a bet at even money on this, I would bet that
>> this code would actually work on a platform chosen at random.
>> But, if what you're looking for is code that is within the bounds
>> of the Standard requires to work portably, this approach isn't it.

>
> I prefer portable code, but I don't want to take it to the extreme
> either.


That's a tough call. Someone suggested putting the pointers into a
union instead of the structures. That works but it is not very
convenient unless you can use C99's compound literals at the point of
call. Of course, using compound literals has portability implications
too.

--
Ben.
 
Reply With Quote
 
Joel C. Salomon
Guest
Posts: n/a
 
      02-25-2011
Jef Driesen wrote:
> I suppose the correct way would be to cast only to the correct type:
>
> void myfunction (data_type_t type, void *data)
> {
> foo_t *foo = NULL;
> bar_t *bar = NULL;
>
> switch (type) {
> case DATA_TYPE_FOO:
> foo = data;
> /* Use foo here */
> break:
> case DATA_TYPE_BAR:
> foo = data;
> /* Use bar here */
> break:
> default:
> return;
> }
> }


Why not try this:

void myfunction (data_type_t type, void *data) {
switch (type) {
case DATA_TYPE_FOO:
foo_t *foo = data;
/* use foo here */
break;
case DATA_TYPE_BAR:
bar_t *bar = data;
/* Use bar here */
break;
default:
return;
}
}

i.e., only even defining `foo` & `bar` where they are needed.
01234567890123456789012345678901234567890123456789 0123456789012345678901234|6789
(Well actually, `foo` is in-scope but uninitialized in the `bar` case. The
compiler might well catch it if you accidentally use it there, or you can add
blocks, e.g.,


case DATA_TYPE_BAR: {
bar_t *bar = data;
/* Use bar here */
} break;


and you can use this technique in a pre-C99 compiler, too.)

—Joel

 
Reply With Quote
 
Tim Rentsch
Guest
Posts: n/a
 
      02-25-2011
Jef Driesen <(E-Mail Removed)> writes:

> On 24/02/11 22:02, Tim Rentsch wrote:
>> Jef Driesen<(E-Mail Removed)> writes:
>>
>>> Hi,
>>>
>>> Suppose I have two distinct data structures:
>>>
>>> typedef struct foo_t {
>>> ...
>>> } foo_t;
>>>
>>> typedef struct bar_t {
>>> ...
>>> } bar_t;
>>>
>>> and a function that receives a pointer to such a structure, together
>>> with a type to indicate which structure is being passed:
>>>
>>> typedef enum data_type_t {
>>> DATA_TYPE_FOO,
>>> DATA_TYPE_BAR
>>> } data_type_t;
>>>
>>> void myfunction (data_type_t type, void *data)
>>> {
>>> foo_t *foo = data;
>>> foo_t *bar = data;
>>>
>>> switch (type) {
>>> case DATA_TYPE_FOO:
>>> /* Use foo here */
>>> break:
>>> case DATA_TYPE_BAR:
>>> /* Use bar here */
>>> break:
>>> default:
>>> return;
>>> }
>>> }
>>>
>>> A typical usage would be like this:
>>>
>>> int main(void)
>>> {
>>> foo_t foo;
>>> bar_t bar;
>>>
>>> myfunction (DATA_TYPE_FOO,&foo);
>>> myfunction (DATA_TYPE_BAR,&bar);
>>>
>>> return 0;
>>> }
>>>
>>> Is it portable to replace the separate variables and explicit casts with a union?
>>>
>>> typedef union foobar_t {
>>> bar_t bar;
>>> foo_t foo;
>>> } foobar_t;
>>>
>>> void myfunction (data_type_t type, void *data)
>>> {
>>> foobar_t *foobar = data;
>>>
>>> switch (type) {
>>> case DATA_TYPE_FOO:
>>> /* Use foobar->foo here */
>>> break:
>>> case DATA_TYPE_BAR:
>>> /* Use foobar->bar here */
>>> break:
>>> default:
>>> return;
>>> }
>>> }
>>>
>>> I think this is a portable construct, but I'm not 100% sure. Note that
>>> it's not my intent to try to interpret a foo_t as a bar_t. The main
>>> purpose of the union is to improve the readability of the code (my
>>> real code has many more foo and bar structs).

>>
>> If called from your example main() function above, technically
>> this last function crosses over into undefined behavior. In
>> fact the undefined behavior happens even before getting to
>> the switch() statement.
>>
>> To see why this is true, remember what we did: we took a
>> pointer to a foo_t or bar_t, and converted that to a 'void *'.
>> Okay, nothing wrong with that. But then, in the revised
>> myfunction(), we took the 'void *' pointer value and converted
>> it to a pointer to a foobar_t (the union type). The union type
>> may have (ie, the Standard allows it to have) a more restrictive
>> alignment requirement than the struct types. Hence, upon doing
>> the conversion of a struct pointer (in the guise of a 'void *',
>> but still pointing to one of the structs), we could get a pointer
>> that is not correctly aligned for access to the union type. The
>> Standard says clearly that if the resulting pointer value is not
>> correctly aligned for the target type then the behavior is
>> undefined.

>
> If this is indeed a potential problem, then why doesn't the same logic
> apply to my first example too? Here I did cast the data pointer to all
> possible struct types, while only one of them will be the correct one:
>
> foo_t *foo = data;
> bar_t *bar = data;
>
> Assuming the real type was of type foo_t, the bar variable may now
> point to a struct which may have different alignment requirements. Or
> am I seeing this wrong?


You're right, this usage is also undefined behavior. I didn't
notice earlier because I was focused on the question about using
unions.


> I suppose the correct way would be to cast only to the correct type:
>
> void myfunction (data_type_t type, void *data)
> {
> foo_t *foo = NULL;
> bar_t *bar = NULL;
>
> switch (type) {
> case DATA_TYPE_FOO:
> foo = data;
> /* Use foo here */
> break:
> case DATA_TYPE_BAR:
> foo = data;
> /* Use bar here */
> break:
> default:
> return;
> }
> }
>
> or get rid of the foo and bar variables and cast the data pointer
> everywhere where it is accessed:
>
> ((foo_t *) data)->member
>
> But this is ugly and error-prone, especially when you have to do this cast often.
>
>> If I had to take a bet at even money on this, I would bet that
>> this code would actually work on a platform chosen at random.
>> But, if what you're looking for is code that is within the bounds
>> of the Standard requires to work portably, this approach isn't it.

>
> I prefer portable code, but I don't want to take it to the extreme either.


How about this way (please excuse a minor reformating):

void
myfunction( data_type_t type, void *data ){
switch (type) {

case DATA_TYPE_FOO: {
foo_t *foo = data;
/* Use foo here */
break:
}

case DATA_TYPE_BAR: {
bar_t *bar = data;
/* Use bar here */
break:
}

}
}

Not too bad aesthetics-wise, and completely portable (assuming of
course the calls are right).
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
struct/union pointer/address stuff. Kenneth Bull C Programming 1 04-15-2008 10:28 AM
Struct/Union pointer stuff Kenneth Bull C Programming 1 04-14-2008 06:01 AM
pointer, union, something... zacariaz@gmail.com C++ 8 09-18-2007 11:45 PM
union in struct without union name Peter Dunker C Programming 2 04-26-2004 07:23 PM
map XML union to C union (and vice-versa) Matt Garman XML 1 04-25-2004 12:40 AM



Advertisments