Typecasting Pointers

Discussion in 'C Programming' started by brian, Nov 23, 2004.

  1. brian

    brian Guest

    Quick question:

    if I have a structure:

    struct foo {

    unsigned char *packet;
    unsigned char *ip_src;
    };

    and another structure:

    struct foo2 {

    unsigned char *packet;
    };

    and I do:

    struct foo *a;
    struct foo2 *b;

    a = malloc(sizeof(struct foo));
    if (a == NULL)
    return NULL;

    (void)memset(a, 1, sizeof(struct foo));

    b = (struct foo2 *)a;

    --

    Would foo2 just strip off the *packet?

    And what happens to *ip?

    I am trying to understand how C handles the typecast if
    one structure pointed to has a different number of members
    than the other. I am trying to understand how C99 treats
    this situation. Both of my pointers should be correctly
    aligned.

    Thanks,

    Brian
     
    brian, Nov 23, 2004
    #1
    1. Advertising

  2. brian

    brian Guest

    Jack Klein wrote:
    [snip]
    > You put "-- ", which is a usenet and email signature delimiter, in the
    > middle of your post. My newsreader quite properly snipped it, and
    > everything that followed it. And like an awful lot of people these
    > days, you did not put a signature delimiter before your actual
    > signature. Sigh.
    >
    > In any case, about the only guarantee that you have is based on the
    > fact that a pointer to a structure, when suitably cast, points to the
    > structure's first member. That means that on most platforms, you can
    > cast a pointer to either type of structure to a pointer to pointer to
    > char and use it to access the first member of each structure, which is
    > a pointer to char.
    >
    > Anything beyond that is undefined behavior. Here is the relevant
    > paragraph from C99:
    >
    > ========
    > 6.2.7 Compatible type and composite type
    > 1 Two types have compatible type if their types are the same.
    > Additional rules for determining whether two types are compatible are
    > described in 6.7.2 for type specifiers, in 6.7.3 for type qualifiers,
    > and in 6.7.5 for declarators.46) Moreover, two structure, union, or
    > enumerated types declared in separate translation units are compatible
    > if their tags and members satisfy the following requirements: If one
    > is declared with a tag, the other shall be declared with the same tag.
    > If both are complete types, then the following additional requirements
    > apply: there shall be a one-to-one correspondence between their
    > members such that each pair of corresponding members are declared with
    > compatible types, and such that if one member of a corresponding pair
    > is declared with a name, the other member is declared with the same
    > name. For two structures, corresponding members shall be declared in
    > the same order. For two structures or unions, corresponding bit-fields
    > shall have the same widths. For two enumerations, corresponding
    > members shall have the same values.
    > ========
    >


    Thanks for your help. I will post in this format:

    [quoted post]
    [my post]
    [dashes]
    [sig]

    So as long as both pointers start on the same alignment boundary, I
    should be fine with the cast. I will just be sure to include cast
    alignment (-Wcast-align) warnings when I compile.

    ------

    Thanks,

    Brian
     
    brian, Nov 24, 2004
    #2
    1. Advertising

  3. brian

    Jack Klein Guest

    On Tue, 23 Nov 2004 14:03:36 -0700, brian <> wrote in
    comp.lang.c:

    > Quick question:
    >
    > if I have a structure:
    >
    > struct foo {
    >
    > unsigned char *packet;
    > unsigned char *ip_src;
    > };
    >
    > and another structure:
    >
    > struct foo2 {
    >
    > unsigned char *packet;
    > };
    >
    > and I do:
    >
    > struct foo *a;
    > struct foo2 *b;
    >
    > a = malloc(sizeof(struct foo));
    > if (a == NULL)
    > return NULL;
    >
    > (void)memset(a, 1, sizeof(struct foo));
    >
    > b = (struct foo2 *)a;


    You put "-- ", which is a usenet and email signature delimiter, in the
    middle of your post. My newsreader quite properly snipped it, and
    everything that followed it. And like an awful lot of people these
    days, you did not put a signature delimiter before your actual
    signature. Sigh.

    In any case, about the only guarantee that you have is based on the
    fact that a pointer to a structure, when suitably cast, points to the
    structure's first member. That means that on most platforms, you can
    cast a pointer to either type of structure to a pointer to pointer to
    char and use it to access the first member of each structure, which is
    a pointer to char.

    Anything beyond that is undefined behavior. Here is the relevant
    paragraph from C99:

    ========
    6.2.7 Compatible type and composite type
    1 Two types have compatible type if their types are the same.
    Additional rules for determining whether two types are compatible are
    described in 6.7.2 for type specifiers, in 6.7.3 for type qualifiers,
    and in 6.7.5 for declarators.46) Moreover, two structure, union, or
    enumerated types declared in separate translation units are compatible
    if their tags and members satisfy the following requirements: If one
    is declared with a tag, the other shall be declared with the same tag.
    If both are complete types, then the following additional requirements
    apply: there shall be a one-to-one correspondence between their
    members such that each pair of corresponding members are declared with
    compatible types, and such that if one member of a corresponding pair
    is declared with a name, the other member is declared with the same
    name. For two structures, corresponding members shall be declared in
    the same order. For two structures or unions, corresponding bit-fields
    shall have the same widths. For two enumerations, corresponding
    members shall have the same values.
    ========

    --
    Jack Klein
    Home: http://JK-Technology.Com
    FAQs for
    comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
    comp.lang.c++ http://www.parashift.com/c -faq-lite/
    alt.comp.lang.learn.c-c++
    http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html
     
    Jack Klein, Nov 24, 2004
    #3
  4. brian

    Richard Bos Guest

    Jack Klein <> wrote:

    > On Tue, 23 Nov 2004 14:03:36 -0700, brian <> wrote in
    > comp.lang.c:
    >
    > > Quick question:


    [ Snip ]

    > > b = (struct foo2 *)a;

    >
    > You put "-- ", which is a usenet and email signature delimiter, in the
    > middle of your post.


    No, he didn't; that line did not contain a space.

    > My newsreader quite properly snipped it, and everything that followed it.


    Get a better newsreader. Forte Free Agent didn't snip a thing.

    (Yes, I know.)

    > And like an awful lot of people these days, you did not put a
    > signature delimiter before your actual signature. Sigh.


    YMMV, but I do not consider a single name to be a signature...

    > --
    > Jack Klein
    > Home: http://JK-Technology.Com
    > FAQs for
    > comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
    > comp.lang.c++ http://www.parashift.com/c -faq-lite/
    > alt.comp.lang.learn.c-c++
    > http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html


    ....and yours is far from McQ. I wouldn't have complained about that,
    but...

    Richard
     
    Richard Bos, Nov 24, 2004
    #4
  5. brian

    brian Guest

    Keith Thompson wrote:
    [snip]
    > I see that you're using Mozilla Thunderbird 0.5 (consider upgrading to
    > 0.9). If you read its documentation, it should tell you how to set up
    > a signature file (probably called ".signature" that will automatically
    > be included, with the proper delimiter, at the bottom of each post.


    I am using the latest available openBSD port of Thunderbird. I know
    there is a later version, but I do not have the time to security audit
    the latest version, nor do I know the C standard well enough to do a
    good job. I am okay with using out of date software that has
    been audited.

    Also, I really have no need for a signature. My name should be enough.
    It doesn't take that long to type five characters.

    If you have suggestions for other e-mail/newsreaders, I will check the
    port list and try using one of those. openBSD doesn't have the most
    extensive collection of ports or most up to date, but the ports work.

    Brian

    ps Am I good concerning the typecast? I was a little unsure of the
    standard and wanted to verify my understanding.
     
    brian, Nov 24, 2004
    #5
  6. brian <> writes:
    [snip]
    > Thanks for your help. I will post in this format:
    >
    > [quoted post]
    > [my post]
    > [dashes]
    > [sig]
    >
    > So as long as both pointers start on the same alignment boundary, I
    > should be fine with the cast. I will just be sure to include cast
    > alignment (-Wcast-align) warnings when I compile.
    >
    > ------
    >
    > Thanks,
    >
    > Brian


    The standard signature delimiter is a line consisting of two hyphens
    and a single trailing space. A line of six hyphens is just a line of
    six hyphens.

    I see that you're using Mozilla Thunderbird 0.5 (consider upgrading to
    0.9). If you read its documentation, it should tell you how to set up
    a signature file (probably called ".signature" that will automatically
    be included, with the proper delimiter, at the bottom of each post.

    And incidentally, it's seldom necessary to quote the entire post to
    which you're responding. Trim out anything that's not relevant to
    your followup. See most of the articles in this newsgroup for good
    examples.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    We must do something. This is something. Therefore, we must do this.
     
    Keith Thompson, Nov 24, 2004
    #6
  7. brian

    brian Guest

    Barry Schwarz wrote:
    > On Tue, 23 Nov 2004 14:03:36 -0700, brian <> wrote:

    [snip]

    >>(void)memset(a, 1, sizeof(struct foo));


    This should be to 0 or NULL. My mistake.

    [snip]

    >>I am trying to understand how C handles the typecast if
    >>one structure pointed to has a different number of members
    >>than the other. I am trying to understand how C99 treats

    >
    >
    > This makes no sense. The only thing being typecast is a pointer to
    > struct and not a struct itself. A pointer doesn't care about the size
    > of or quantity of members in the struct it points to.


    I understand that I am just typecasting pointers. I was just trying to
    confirm that the following holds true:

    [struct foo * ][member 1][member 2]

    [struct foo2 *][member 1]

    that the memory addresses will overlap, so I can use a struct foo2
    pointer to access the values in struct foo member 1 after I have
    assigned values to whatever is pointed to. That the address of the
    first member in foo will be the same address in foo2 by virtue of
    malloc(). I'm sorry for not being more clear.

    [snip]

    > The assignment would still be legal since the standard
    > requires all pointers to struct to have the same alignment and
    > representation but you cannot dereference b portably.


    And I cannot dereference portably because the alignment restrictions
    could be different?

    Thanks,

    brian
     
    brian, Nov 24, 2004
    #7
  8. On Tue, 23 Nov 2004 14:03:36 -0700, brian <> wrote:

    >Quick question:
    >
    >if I have a structure:
    >
    >struct foo {
    >
    > unsigned char *packet;
    > unsigned char *ip_src;
    >};
    >
    >and another structure:
    >
    >struct foo2 {
    >
    > unsigned char *packet;
    >};
    >
    >and I do:
    >
    >struct foo *a;
    >struct foo2 *b;
    >
    >a = malloc(sizeof(struct foo));
    >if (a == NULL)
    > return NULL;


    So a now points to a dynamically allocated struct foo.

    >
    >(void)memset(a, 1, sizeof(struct foo));


    This sets every byte of that struct to the value 1. Since the struct
    consists of nothing but pointers, odds are that none of the members of
    the struct contain a useful (or even valid) value.

    >
    >b = (struct foo2 *)a;


    The address returned by malloc is guaranteed to be properly aligned
    for any object so b is valid and you can use it to treat the area as a
    struct foo2.

    >Would foo2 just strip off the *packet?


    foo2 is the tag for a struct. It doesn't "do" anything. The address
    that b points is the start of a struct foo and is guaranteed to be the
    address of the member packet in that struct. It also happens to be
    the start of a mythical struct foo2 and is therefore also the address
    of the member packet in that struct.

    >
    >And what happens to *ip?


    It is still there in the allocated area. Assigning the value in a to
    the pointer b did nothing to the data in the area a points to.

    >
    >I am trying to understand how C handles the typecast if
    >one structure pointed to has a different number of members
    >than the other. I am trying to understand how C99 treats


    This makes no sense. The only thing being typecast is a pointer to
    struct and not a struct itself. A pointer doesn't care about the size
    of or quantity of members in the struct it points to.

    >this situation. Both of my pointers should be correctly
    >aligned.


    The pointers are correctly aligned by virtue of malloc. If you had
    coded
    struct foo x;
    a = &x;
    b = (struct foo2*)a;
    there would be no guarantee that b would be correctly aligned for a
    struct foo2. The assignment would still be legal since the standard
    requires all pointers to struct to have the same alignment and
    representation but you cannot dereference b portably.



    <<Remove the del for email>>
     
    Barry Schwarz, Nov 25, 2004
    #8
  9. brian

    brian Guest

    Barry Schwarz wrote:

    [snip]
    >>>>(void)memset(a, 1, sizeof(struct foo));

    >>
    >>This should be to 0 or NULL. My mistake.

    >
    >
    > Not really. NULL would not portable because some systems define NULL
    > to be (void*)0. 0 is not portable either since their is no guarantee
    > that a pointer value of all bits 0 has any meaning.


    Then, what is the best way to initialize the structure? Should I even
    bother? Now, I'm really stuck on this piece.

    [snip]
    >
    > There is only one address, the one returned by malloc. The fact that
    > you have stored this address in two different pointers doesn't change
    > that.


    Awesome. I just wanted to confirm this to be true with that cast. I
    wasn't sure after reading the standard.

    [snip]
    >
    >>And I cannot dereference portably because the alignment restrictions
    >>could be different?

    >
    >
    > Yup.


    That stinks. I designed my program to have a structure in my header
    file, and I used functions prototypes like

    int somefunc(struct foo **);

    to pass the structure around the program after allocating space for it.
    Is there a portable way to pass variable values around a program?

    Brian
     
    brian, Nov 25, 2004
    #9
  10. brian

    Flash Gordon Guest

    On Wed, 24 Nov 2004 13:59:50 -0700
    brian <> wrote:

    > Barry Schwarz wrote:
    > > On Tue, 23 Nov 2004 14:03:36 -0700, brian <> wrote:

    > [snip]
    >
    > >>(void)memset(a, 1, sizeof(struct foo));

    >
    > This should be to 0 or NULL. My mistake.


    <snip>

    That doesn't help much. Since the second argument is an int and NULL
    could be ((void *)0) a call of
    (void)memset(a, NULL, sizeof(struct foo));
    could require a diagnostic.

    Even a 0 does not help much as this would set it to all bits 0 and all
    bits 0 might not be the correct value.
    --
    Flash Gordon
    Living in interesting times.
    Although my email address says spam, it is real and I read it.
     
    Flash Gordon, Nov 26, 2004
    #10
  11. On Wed, 24 Nov 2004 13:59:50 -0700, brian <> wrote:

    >Barry Schwarz wrote:
    >> On Tue, 23 Nov 2004 14:03:36 -0700, brian <> wrote:

    >[snip]
    >
    >>>(void)memset(a, 1, sizeof(struct foo));

    >
    >This should be to 0 or NULL. My mistake.


    Not really. NULL would not portable because some systems define NULL
    to be (void*)0. 0 is not portable either since their is no guarantee
    that a pointer value of all bits 0 has any meaning.

    >
    >[snip]
    >
    >>>I am trying to understand how C handles the typecast if
    >>>one structure pointed to has a different number of members
    >>>than the other. I am trying to understand how C99 treats

    >>
    >>
    >> This makes no sense. The only thing being typecast is a pointer to
    >> struct and not a struct itself. A pointer doesn't care about the size
    >> of or quantity of members in the struct it points to.

    >
    >I understand that I am just typecasting pointers. I was just trying to
    >confirm that the following holds true:
    >
    >[struct foo * ][member 1][member 2]
    >
    >[struct foo2 *][member 1]
    >
    >that the memory addresses will overlap, so I can use a struct foo2
    >pointer to access the values in struct foo member 1 after I have
    >assigned values to whatever is pointed to. That the address of the
    >first member in foo will be the same address in foo2 by virtue of
    >malloc(). I'm sorry for not being more clear.


    There is only one address, the one returned by malloc. The fact that
    you have stored this address in two different pointers doesn't change
    that.

    >
    >[snip]
    >
    > > The assignment would still be legal since the standard
    >> requires all pointers to struct to have the same alignment and
    >> representation but you cannot dereference b portably.

    >
    >And I cannot dereference portably because the alignment restrictions
    >could be different?


    Yup.



    <<Remove the del for email>>
     
    Barry Schwarz, Nov 26, 2004
    #11
  12. On Thu, 25 Nov 2004 11:52:04 -0700, brian <> wrote:

    >Barry Schwarz wrote:
    >
    >[snip]
    >>>>>(void)memset(a, 1, sizeof(struct foo));
    >>>
    >>>This should be to 0 or NULL. My mistake.

    >>
    >>
    >> Not really. NULL would not portable because some systems define NULL
    >> to be (void*)0. 0 is not portable either since their is no guarantee
    >> that a pointer value of all bits 0 has any meaning.

    >
    >Then, what is the best way to initialize the structure? Should I even
    >bother? Now, I'm really stuck on this piece.


    If you define the structure, you can initialize it as part of the
    definition:
    struct foo a = {0};
    This will cause each member of the struct to be set to the appropriate
    zero value ('\0' for char, 0 for integers, 0.0 floating points, and
    NULL for pointers.

    If you allocate the struct, as was done up-thread, then you don't have
    much choice but to do it member by member. However, if you have a
    defined struct that was initialized, you can initialize the allocated
    one by a simple assignment:
    struct foo *b = malloc(sizeof *b);
    b = a;

    >
    >[snip]
    >>
    >> There is only one address, the one returned by malloc. The fact that
    >> you have stored this address in two different pointers doesn't change
    >> that.

    >
    >Awesome. I just wanted to confirm this to be true with that cast. I
    >wasn't sure after reading the standard.
    >
    >[snip]
    >>
    >>>And I cannot dereference portably because the alignment restrictions
    >>>could be different?

    >>
    >>
    >> Yup.

    >
    >That stinks. I designed my program to have a structure in my header
    >file, and I used functions prototypes like


    A header file should have only the struct declaration, not any
    definition.

    >
    >int somefunc(struct foo **);
    >
    >to pass the structure around the program after allocating space for it.


    Why would you use a pointer to pointer to struct when a simple pointer
    to struct will let the function update the members at will? The
    struct ** makes sense if the function will allocate the struct so it
    can update the pointer directly but your comment says the struct is
    already allocated.

    > Is there a portable way to pass variable values around a program?


    Function arguments seem to work for most cases.

    WHY do you want the address of a struct foo to be treated as the
    address of a struct foo2? You might want to consider embedding both
    structs in a union.


    <<Remove the del for email>>
     
    Barry Schwarz, Nov 27, 2004
    #12
  13. On Fri, 26 Nov 2004 23:06:37 -0800, Barry Schwarz <>
    wrote:

    >On Thu, 25 Nov 2004 11:52:04 -0700, brian <> wrote:
    >
    >>Barry Schwarz wrote:
    >>
    >>[snip]
    >>>>>>(void)memset(a, 1, sizeof(struct foo));
    >>>>
    >>>>This should be to 0 or NULL. My mistake.
    >>>
    >>>
    >>> Not really. NULL would not portable because some systems define NULL
    >>> to be (void*)0. 0 is not portable either since their is no guarantee
    >>> that a pointer value of all bits 0 has any meaning.

    >>
    >>Then, what is the best way to initialize the structure? Should I even
    >>bother? Now, I'm really stuck on this piece.

    >
    >If you define the structure, you can initialize it as part of the
    >definition:
    > struct foo a = {0};
    >This will cause each member of the struct to be set to the appropriate
    >zero value ('\0' for char, 0 for integers, 0.0 floating points, and
    >NULL for pointers.
    >
    >If you allocate the struct, as was done up-thread, then you don't have
    >much choice but to do it member by member. However, if you have a
    >defined struct that was initialized, you can initialize the allocated
    >one by a simple assignment:
    > struct foo *b = malloc(sizeof *b);
    > b = a;


    That should be *b = a;


    <<Remove the del for email>>
     
    Barry Schwarz, Nov 27, 2004
    #13
  14. In article <tZwpd.95065$SW3.12565@fed1read01>, brian <> writes:
    > Barry Schwarz wrote:
    > > [brian wrote:]
    > >>>>(void)memset(a, 1, sizeof(struct foo));
    > >>
    > >>This should be to 0 or NULL. My mistake.

    > >
    > >
    > > Not really. NULL would not portable because some systems define NULL
    > > to be (void*)0. 0 is not portable either since their is no guarantee
    > > that a pointer value of all bits 0 has any meaning.

    >
    > Then, what is the best way to initialize the structure? Should I even
    > bother? Now, I'm really stuck on this piece.


    There are various alternatives, but I prefer structure assignment with
    a static const initializer:

    #include <stdlib.h>

    static struct foo *alloc_foo(void)
    {
    static const struct foo foo0 = {0};
    struct foo *newfoo = malloc(sizeof *newfoo);

    if (newfoo)
    *newfoo = foo0;

    return newfoo;
    }

    The {0} is actually unnecessary, since static variables without an
    explicit initializer are implicitly initialized to {0}, but I prefer
    to make it explicit.

    If multiple functions in a file need the initializer, put it at file
    scope. If functions in multiple files need the initializer, you
    could make it non-static, with an extern declaration in the header
    that defines struct foo, but that raises issues of constraints on
    and collisions of externally-visible names, so in some cases it may
    be better simply to define one initializer per file (or refactor so
    that only one file ever initializes dynamically-allocated variables
    of that type - often the best choice).

    By the way, returning to the question of Usenet signatures: your
    messages should include a proper signature delimiter (a line
    containing only two hyphens and a space) before your signature,
    even if it only includes your name.

    --
    Michael Wojcik

    Is it any wonder the world's gone insane, with information come to be
    the only real medium of exchange? -- Thomas Pynchon
     
    Michael Wojcik, Nov 29, 2004
    #14
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    3
    Views:
    617
    Emmanuel Delahaye
    Jul 15, 2005
  2. typecasting of function pointers

    , Mar 20, 2006, in forum: C Programming
    Replies:
    12
    Views:
    943
    Flash Gordon
    Mar 21, 2006
  3. Replies:
    12
    Views:
    627
    Stephen Sprunk
    Aug 8, 2006
  4. Nishu

    Typecasting pointers

    Nishu, Jan 29, 2007, in forum: C Programming
    Replies:
    26
    Views:
    1,379
    Bernhard Holzmayer
    Jan 30, 2007
  5. Quentin Pope

    Typecasting Pointers on a 64 bit System

    Quentin Pope, Nov 10, 2011, in forum: C Programming
    Replies:
    54
    Views:
    1,594
    Phil Carmody
    Nov 18, 2011
Loading...

Share This Page