cast pointer to struct to pointer to type of first member of struct 
Author Message
 cast pointer to struct to pointer to type of first member of struct

Hi. Does the code below have well-defined behavior,
especially the line marked with "?"?

typedef int Some_Type;

struct node {
    void *next;
    Some_Type data;

Quote:
};

int main(void)
{
    struct node first, second;
    *(void**)&first = &second;    /* ? */
    return 0;

Quote:
}

I need to do something like this because my program should deal with
nodes which vary in the type of the second member.


Sun, 28 Nov 2004 23:10:43 GMT  
 cast pointer to struct to pointer to type of first member of struct

Quote:

> Hi. Does the code below have well-defined behavior,
> especially the line marked with "?"?

> typedef int Some_Type;

> struct node {
>     void *next;
>     Some_Type data;
> };

> int main(void)
> {
>     struct node first, second;
>     *(void**)&first = &second;    /* ? */
>     return 0;
> }

> I need to do something like this because my program should deal with
> nodes which vary in the type of the second member.

Perhaps I am not understanding your question, but if you want a pointer
to the first member of "first" then you can do this:
void *myptr;
myptr = first.next;

If you want a first to point to second you can do this:
struct node *first,second;
first = &second;

If you want first to be a copy of second you can do this:
/* after including string.h */
struct node first, second;
memcpy((void*)&first,(void*)&second,sizeof(second));

Hope this helps,
Sam Reynolds



Mon, 29 Nov 2004 01:06:30 GMT  
 cast pointer to struct to pointer to type of first member of struct
On Wed, 12 Jun 2002 17:10:43 +0200, Martin F. said:

Quote:
> Hi. Does the code below have well-defined behavior,
> struct node {
>     void *next;
>     Some_Type data;
> };

>     struct node first, second;
>     *(void**)&first = &second;    /* ? */

I'm having difficulty even seeing what the l-value that you want
is... it seems like you want to do something like
first.next = &second;
which would be OK, I think. You're assigning a pointer-to-struct
to a void * which is allowed, as long as you convert it back
before dereferencing.

Dissecting the lhs: &first: pointer to a struct (which can be
converted to a pointer to the first element of the struct).
(void **)&first: pointer to struct cast to void**, which is a
pointer to the first element of the struct.
&(void **)&first: The first element of the struct.

Why do that, rather than refer to it as first.next?

Quote:
> I need to do something like this because my program should deal with
> nodes which vary in the type of the second member.

I don't see why this is causing you an issue...

Dave.

--
           David Neary,
     E-Mail: bolsh at gimp dot org
CV: http://www.redbrick.dcu.ie/~bolsh/CV/CV.html



Mon, 29 Nov 2004 02:11:00 GMT  
 cast pointer to struct to pointer to type of first member of struct

Quote:

> Hi. Does the code below have well-defined behavior,
> especially the line marked with "?"?

> typedef int Some_Type;

> struct node {
>     void *next;
>     Some_Type data;
> };

> int main(void)
> {
>     struct node first, second;
>     *(void**)&first = &second;    /* ? */
>     return 0;
> }

> I need to do something like this because my program should deal with
> nodes which vary in the type of the second member.

Declare a struct to hold your data together

struct link{
   struct link *next;
   int type;    /* tells in what kind of struct link_X this belongs */

Quote:
};

and a struct link_X for each type you want to link:

struct link_int{
   struct link link; /* Needs to be the first element */
   int x;

Quote:
};

struct link_double{
   struct link link;
   double x;

Quote:
};

You can walk your list using pointers to link, and if you want to do
something with a particular link, you can determine the type of data and
cast accordingly:

void apply_to_doubles(struct link *head_p,void fcn(struct link_double *)){
   for(;head_p!=NULL;head_p=head_p->next){
      if(head_p->type == DOUBLE_TYPE){
         fcn((struct link_double *)head_p);
      }
   }

Quote:
}

You could also devise a more genearal linked list facility by adding a void
*data; to struct link{}; and malloc the memory for each elemant. This is
probably more flexible, but has other disadvantages: two mallocs to add a
link, and one more pointer indirection to access the data.
Tobias.

--
unix http://www.faqs.org/faqs/by-newsgroup/comp/comp.unix.programmer.html
clc http://www.eskimo.com/~scs/C-faq/top.html
fclc (french): http://www.isty-info.uvsq.fr/~rumeau/fclc/



Mon, 29 Nov 2004 02:20:34 GMT  
 cast pointer to struct to pointer to type of first member of struct


Wed, 18 Jun 1902 08:00:00 GMT  
 cast pointer to struct to pointer to type of first member of struct

Quote:


> > Hi. Does the code below have well-defined behavior,
> > especially the line marked with "?"?

> > typedef int Some_Type;

> > struct node {
> >     void *next;
> >     Some_Type data;
> > };

> > int main(void)
> > {
> >     struct node first, second;
> >     *(void**)&first = &second;    /* ? */

Assigning to something through an incompatible pointer type is a Very Bad
Idea (VBI).

Quote:
> >     return 0;
> > }

<snip - see below>

Quote:
> If you want first to be a copy of second you can do this:
> /* after including string.h */
> struct node first, second;
> memcpy((void*)&first,(void*)&second,sizeof(second));

Yikes!
first = second;
would suffice.  And it would be free of useless casts.

I suspect what OP actually needs is a new version of his node struct.
From his comments:

Quote:
> I need to do something like this because my program should deal with
> nodes which vary in the type of the second member.

I conclude that each node may contain a differently-typed payload (not all
ints).

Quote:
> typedef int Some_Type;

> struct node {
>     void *next;
>     Some_Type data;
> };

You've got the right idea using a void*, but you should use it to hold the
*data*, (as opposed to the pointer-to-next-node),  for it is the member
with variable type.
Like this:

struct node {
   struct node *next;
   void *data;
   /* maybe an enum to keep track of what we point to */

Quote:
}

int main(void) {
   struct node first = {0}, second = {0}, third = {0};
   struct node *head = NULL;

   /* first will hold an array of twenty ints */
   first.data = malloc(20 * sizeof (int) );
   /* second will hold a struct foo */
   second.data = malloc(sizeof (struct foo) );
   /* third will hold a 512-byte string */
   third.data = malloc(512);
   /* test then fill allocated memory */

   /* now build a list out of the nodes */
   head = &first;  first->next = &second;  second->next = &third;
   /* don't forget to free() datas */

Quote:
}

Hope that helps,
Ryan.


Mon, 29 Nov 2004 02:32:52 GMT  
 cast pointer to struct to pointer to type of first member of struct


Wed, 18 Jun 1902 08:00:00 GMT  
 cast pointer to struct to pointer to type of first member of struct

Quote:


(snip)

>> I need to do something like this because my program should deal
>> with nodes which vary in the type of the second member.

> Declare a struct to hold your data together

> struct link{
>    struct link *next;
>    int type;    /* tells in what kind of struct link_X this belongs
>    */
> };

> and a struct link_X for each type you want to link:

> struct link_int{
>    struct link link; /* Needs to be the first element */
>    int x;
> };

> struct link_double{
>    struct link link;
>    double x;
> };

> You can walk your list using pointers to link, and if you want to do
> something with a particular link, you can determine the type of data
> and cast accordingly:

> void apply_to_doubles(struct link *head_p,void fcn(struct
> link_double *)){
>    for(;head_p!=NULL;head_p=head_p->next){
>       if(head_p->type == DOUBLE_TYPE){
>          fcn((struct link_double *)head_p);
>       }
>    }
> }

This is good, but then I have to limit my list functions to a finite
set of types. I would like them to be usable with *any* object type.

Quote:
> You could also devise a more genearal linked list facility by adding
> a void *data; to struct link{}; and malloc the memory for each
> elemant. This is probably more flexible, but has other
> disadvantages: two mallocs to add a link, and one more pointer
> indirection to access the data.

Yes. The additional (theoretically unnecessary) level of indirection
is the reason why I did not choose this solution. But maybe I should
use it however, because it seems to be the cleanest solution.

Martin



Mon, 29 Nov 2004 03:37:30 GMT  
 cast pointer to struct to pointer to type of first member of struct

Quote:



>> > Hi. Does the code below have well-defined behavior,
>> > especially the line marked with "?"?

>> > typedef int Some_Type;

>> > struct node {
>> >     void *next;
>> >     Some_Type data;
>> > };

>> > int main(void)
>> > {
>> >     struct node first, second;
>> >     *(void**)&first = &second;    /* ? */

> Assigning to something through an incompatible pointer type is a
> Very Bad Idea (VBI).

Is the behavior undefined?
Note that the lvalue on the left hand side of the assignment
expression has type void*, which matches the type of the first member
of first; and the first member of first has the same address as first.

Quote:
>> >     return 0;
>> > }

(snip)

Quote:
> I suspect what OP actually needs is a new version of his node
> struct. From his comments:

>> I need to do something like this because my program should deal
>> with nodes which vary in the type of the second member.

> I conclude that each node may contain a differently-typed payload
> (not all ints).

Yes.

- Show quoted text -

Quote:
>> typedef int Some_Type;

>> struct node {
>>     void *next;
>>     Some_Type data;
>> };

> You've got the right idea using a void*, but you should use it to
> hold the
> *data*, (as opposed to the pointer-to-next-node),  for it is the
> member with variable type.
> Like this:

> struct node {
>    struct node *next;
>    void *data;
>    /* maybe an enum to keep track of what we point to */
> }

> int main(void) {
>    struct node first = {0}, second = {0}, third = {0};
>    struct node *head = NULL;

>    /* first will hold an array of twenty ints */
>    first.data = malloc(20 * sizeof (int) );
>    /* second will hold a struct foo */
>    second.data = malloc(sizeof (struct foo) );
>    /* third will hold a 512-byte string */
>    third.data = malloc(512);
>    /* test then fill allocated memory */

>    /* now build a list out of the nodes */
>    head = &first;  first->next = &second;  second->next = &third;
>    /* don't forget to free() datas */
> }

> Hope that helps,

This is fine, but I would like to avoid the additional level of
indirection. In other words, I prefer the object to reside in the
node itself, not in a seperately allocated region of storage a
pointer to which is stored in the node.
But this aim seems to make things complicated...

Martin



Mon, 29 Nov 2004 03:57:52 GMT  
 cast pointer to struct to pointer to type of first member of struct


Quote:
> Hi. Does the code below have well-defined behavior,
> especially the line marked with "?"?

> typedef int Some_Type;

> struct node {
>     void *next;
>     Some_Type data;
> };

> int main(void)
> {
>     struct node first, second;
>     *(void**)&first = &second;    /* ? */
>     return 0;
> }

Yes, the code is well defined and does what you expect.  A pointer to a
struct, suitably cast, is a pointer to its first element.

I've seen this used to simulate inheritance among structs:

struct base {
  int baseMember;

Quote:
};

struct derived {
  struct base inheritance;
  float derivedMember;

Quote:
};

Functions that expect a pointer-to-struct-base will work with a
pointer-to-struct-derived [1]

Quote:
> I need to do something like this because my program should deal with
> nodes which vary in the type of the second member.

The way I've usually seen this done is to use a union of the various
types:

struct firstType {
   void* next;
   int data;

Quote:
};

struct secondType {
   void* next;
   float data;

Quote:
};

union node {
   void* next;
   struct firstType first;
   struct secondType second;  

Quote:
};

-Peter

[1] This will not be true, of course, if the functions depend the size
of the data pointed to; e.g. attempting to walk an array of struct
derived's given a pointer to a struct base will fail.



Mon, 29 Nov 2004 04:37:57 GMT  
 cast pointer to struct to pointer to type of first member of struct

Quote:




> >> > Hi. Does the code below have well-defined behavior,
> >> > especially the line marked with "?"?

> >> > typedef int Some_Type;

> >> > struct node {
> >> >     void *next;
> >> >     Some_Type data;
> >> > };

> >> > int main(void)
> >> > {
> >> >     struct node first, second;
> >> >     *(void**)&first = &second;    /* ? */

> > Assigning to something through an incompatible pointer type is a
> > Very Bad Idea (VBI).

> Is the behavior undefined?
> Note that the lvalue on the left hand side of the assignment
> expression has type void*, which matches the type of the first member
> of first; and the first member of first has the same address as first.

Ducking your question for just one second, why are you so eager to avoid
referencing the next member?  What's wrong with just:

first->next = &second;

Which I can be *sure* doesn't cause any undefined behaviour, and does
what you seem to want.

Now, let me rewrite what you've done, without suspicious-looking casts on
the
left-hand side of the assignment:

struct node first, second;
/* this is the same value as &first->next, by 6.7.2.3 p.12 */
(void*)(&first);

/* this stores that address in a variable of type (void**)  */
/*  note that &first.next also has type (void**)                   */
void **p = (void*)(&first);
assert(p = &first.next);  /* shouldn't fail */

/* therefore *p is an lvalue of the correct type (void*), */
/*  and the correct value (&first.next)                                */

*p = &second;  /* well defined ? */

If the above line is well-defined, then so is yours.

I have perused the sections in the standard on lvalues and compatible
types, and my *opinion* is that this assignment *is* well-defined.
However, many long, protracted discussions have taken place in this forum
regarding the traps, pitfalls and loopholes that arise when you cast
things.  People have successfully argued that a cast from one pointer
type to another can legitimately add 100-byte offsets in either
direction, just as an example.

Others know the standard back-to-front, and can confirm or deny what I
have said.

<snip>

Quote:

> This is fine, but I would like to avoid the additional level of
> indirection. In other words, I prefer the object to reside in the
> node itself, not in a seperately allocated region of storage a
> pointer to which is stored in the node.
> But this aim seems to make things complicated...

If you need to avoid pointers, you could use a union of all possible
types to
represent the payload.  You'd still need to keep track of the type of the
data held within, just as with a void*, so all you'd be saving is the
extra level of indirection.  Perhaps this is a fair balance against the
complexity of unions, perhaps not.


Mon, 29 Nov 2004 05:07:00 GMT  
 cast pointer to struct to pointer to type of first member of struct


Quote:

>This is fine, but I would like to avoid the additional level of
>indirection. In other words, I prefer the object to reside in the
>node itself, not in a seperately allocated region of storage a
>pointer to which is stored in the node.
>But this aim seems to make things complicated...

>Martin

A simple (but limited) way to do this would be something like this:

struct node {
    struct node *next;
    union {
        char char_value;
        int int_value;
        double double_value;
        /* add whatever other types you need here */
    } data;
    enum {char_type, int_type,
        double_type /* add others here */} type;

Quote:
};

Now the member "type" tells you which type is stored, and the value is
access through .data.char_type for a char, .data.int_type for an int,
etc. Here's a quick example for using this:

void print_list(FILE *fout, struct node *head)
{
    for ( ; head != NULL; head=head->next)
    {
        switch (head->type)
        {
        case char_type:
            fprintf(fout, "%c\n", head->data.char_value);
            break;
        case int_type:
            fprintf(fout, "%d\n", head->data.int_value);
            break;
        case double_type:
            fprintf(fout, "%f\n", head->data.double_value);
            break;
        }
    }

Quote:
}

The problems with this are:

1) It's kind of ugly.
2) The node struct and many supporting functions have to be updated
each time you add a new type.
3) If you add a big type (like an array) you end up wasting a lot of
memory in every node that holds one of the smaller types, since each
node will be large enough to hold your largest type.

-Kevin



Mon, 29 Nov 2004 11:42:09 GMT  
 cast pointer to struct to pointer to type of first member of struct

Quote:


(snip)
>>>>>     *(void**)&first = &second;    /* ? */
(snip)
> Ducking your question for just one second, why are you so eager to
> avoid referencing the next member?  What's wrong with just:

> first->next = &second;

> Which I can be *sure* doesn't cause any undefined behaviour, and
> does what you seem to want.

Consider the following program (especially the function list_insert):

#include <stdlib.h>
#include <stdio.h>

typedef struct {
     void *next;
     int data;

Quote:
} Node_int;

typedef struct {
     void *next;
     double data;

Quote:
} Node_double;

void *list_insert(void *where, size_t nodesz)
{    /* this function works with any node type which has a void* as  
        first member */
     void *new_node;
     new_node = malloc(nodesz);
     if (new_node != NULL) {
          *(void**)new_node = where;    /* <-- here is my cast */
          /* the above really means:  new_node->next = where   */
     }
     return new_node;

Quote:
}

void example_int(void)
{
     Node_int *list, *node;
     int i;

     list = NULL;

     /* fill list by repeatedly prepending nodes */
     for (i = 0; i < 5; ++i) {
          node = list_insert(list, sizeof *node);
          if (node == NULL) break;
          node->data = i;
          list = node;
     }

     /* destructively traverse list */
     while (list != NULL) {
          node = list;
          printf("%d\n", node->data);
          list = node->next;
          free(node);
     }

Quote:
}

void example_double(void) { /* ... */ }

int main(void) {
     example_int();
     return 0;

Quote:
}

The list_insert function needs the cast because of its generality.

Martin



Tue, 30 Nov 2004 02:21:49 GMT  
 cast pointer to struct to pointer to type of first member of struct

Quote:

>           *(void**)new_node = where;    /* <-- here is my cast */
>           /* the above really means:  new_node->next = where   */
> The list_insert function needs the cast because of its generality.

This sentence is not correct. The conversion from type void* to type
void** can also be accomplished by other means than a cast, e.g.:

void **p;
p = new_node;   /* implicit conversion */
*p = where;

Martin



Tue, 30 Nov 2004 02:28:28 GMT  
 cast pointer to struct to pointer to type of first member of struct

Quote:

> 1) It's kind of ugly.
> 2) The node struct and many supporting functions have to be updated
> each time you add a new type.
> 3) If you add a big type (like an array) you end up wasting a lot of
> memory in every node that holds one of the smaller types, since each
> node will be large enough to hold your largest type.

Hi, I was searching this list to find discussions since I happened to see a
simlar case like this in the "C Unleashed" book by Sams publishing.  Their
specific case was the 'trie' type.

I am using a union and an enumerated type to store a collection of
heterogeneous objects within a single structure.  My union however is not
quite as straightforward as your example.  Each union member is a struct
with a few members in just about all of them.

I agree that acessing the actual data through a union is a little tough on
the eyes, but is performing a cast in order to obtain the actual object
much better?  Although you won't have to touch the 'struct node' in order
to add new objects, you still have to touch everything else but that.  It
seems that this is just one step away from using an enumerated type and a
void pointer.

The other side of the coin is the case when many of these objects actually
share common attributes and thus having to only write the common members
once aids maintainability:

struct poly {
     enum obj_type { TYPE_CIRCLE, TYPE_RECT, TYPE_RTTRIANGLE };

     /*
      * Common members to all objects
      */
     char *id;    
     double area;

     union {
         struct {
             double radius;    
         } a;
         struct {
             double width;
             double height;
         } b;
         struct {
             double altitude;
             double width;
         } c;
     };

Quote:
};

If you separated circles, rectangles, and right triangles, you'd have to
maintain the consistent 'id' and 'area' tags in separate declarations.

Don't get me wrong, I see your point, but there are tradeoffs no matter
which way you go.

Thanks,

-Clint



Sun, 12 Dec 2004 03:00:52 GMT  
 
 [ 15 post ] 

 Relevant Pages 

1. pointers to functions in structs which take a pointer to that struct as an arg

2. casting of struct element void pointer casting

3. cast struct to first member?

4. QUESTION: Type casting between struct A superset of struct B

5. memory leak: pointer->pointer->pointer->struct

6. memory Leak: pointer->pointer->pointer->struct

7. Need DllImport expert to convert c++ to c# - same struct pointer in struct

8. struct.array works - struct->pointer not

9. Assign struct to struct via pointer

10. pass struct or pointer to struct ???

11. return a struct, not a struct pointer ?

12. Why pass structs? (not struct pointers)

 

 
Powered by phpBB® Forum Software