Re: confused the address of struct member like this

Discussion in 'C Programming' started by James Kuyper, May 28, 2013.

  1. James Kuyper

    James Kuyper Guest

    On 05/28/2013 05:58 AM, Ed wrote:
    >
    > confused the address of struct member like this
    >
    > #include <stdio.h>
    > #include <string.h>
    >
    > typedef struct Test_tag
    > {
    > int a;
    > char Data[32];
    >
    > } Test;
    >
    >
    > int main(int argc, char *argv[])
    > {
    >
    > Test o;
    > char arr[64];
    > Test *pObj = (Test*) arr;


    You are permitted to convert a pointer to char to a pointer to Test*.
    However, "If the resulting pointer is not correctly aligned for the
    referenced type, the behavior is undefined." (6.3.2.3p7)

    > int* p = (int*)arr;


    The same issue applies here.

    > printf("p:%x, &p:%x\n", p, &p);
    > printf("pObj->Data:%x, &pOjb->Data:%x\n", pObj->Data, &pObj->Data);
    > printf("o.Data:%x, &o.Data:%x\n", o.Data, &o.Data);
    > printf("o.a:%x, &o.a:%x\n", o.a, &o.a);


    The "%x" format specifier is for printing out unsigned int values
    (7.22.6.1p8). The corresponding printf() arguments are pointers to
    various types of objects. If unsigned integers and the pointer types
    you're printing out are of the same size, there's a reasonable chance
    that this might produce reasonable results - which would be unlucky,
    because it deprives you of an opportunity to realize that your code is
    defective.

    It's not just a matter of the value possibly not displaying incorrectly
    (such as could happen if unsigned integers are big-endian, while
    pointers are interpreted as little-endian). The standard says that a
    program that involves such a mis-match has undefined behavior
    (7.21.6.1p9). This isn't just some theoretical issue - if, for instance,
    unsigned int is larger than the corresponding pointer type, then
    printf() will end up trying to access memory that it was not intended to
    access, which could be memory your program doesn't have permission to
    access, in which case your program could get aborted by the operating
    system.

    The correct format for printing pointer values is "%p". However, keep in
    mind that it's specifically for void* pointers. If you pass it a pointer
    of some other type, in principle, the consequences could be just as bad
    as when you used "%x". In practice, your chances of being unlucky enough
    for it to work are significantly better, because systems where all
    pointer types have compatible representations are pretty common. The
    most common alternative is systems where the word size is larger than 1
    byte. On such systems, a pointer to a specific byte must contain both
    the address of the word containing that byte, and an offset within the
    word for that particular bytes. Pointers to types that have alignment
    requirements of 1 word or larger, on the other hand, can be represented
    by a pointer that only identifies the first word of that object.
    Therefore, on such systems, there's a decent chance that sizeof(void*)
    != sizeof(long double*).

    You should have written things like this:

    printf("o.a:%p, &o.a:%p\n", (void*)o.a, (void*)&o.a);

    > return 0;
    > }
    > ===========================================
    > (1) p:22ff00, &p:22fef8
    > (2) pObj->Data:22ff04, &pOjb->Data:22ff04
    > (3) o.Data:22ff44, &o.Data:22ff44
    > (4) o.a:4013b0, &o.a:22ff40
    >
    > my question:
    > why these address are same in (2) and (3)?
    >
    > pObj->Data == &pObj->Data?


    You cannot directly compare pointers to incompatible types, unless one
    of them is void*. You must either convert one point to a type compatible
    with the other pointer's type, or convert both pointers to compatible types.

    Given what I've said above, in principle, the answer to your question is
    that, because the behavior of your program is undefined, it could have
    printed out anything at all, including a copy of your birth certificate.
    It could also have chosen to not print out anything at all, but to
    instead erase the only copy you have of the budget report you've been
    working on for the last week. You should not draw any particular
    conclusions from the particular thing it did choose to print out.

    However, it seems likely that you were using a system where you were
    unlucky enough to have your program work as intended; for these
    particular kinds of problems, that's a pretty common result.
    As a result, the reason why those various pointers showed the same value
    is that they pointed at the same location in memory. &o, &o.Data, and
    &o.Data[0] all point at the beginning of o, since o.Data is the first
    member of o, and o.Data[0] is the element of o.Data.
    --
    James Kuyper
     
    James Kuyper, May 28, 2013
    #1
    1. Advertising

  2. James Kuyper <> writes:
    [...]
    > The correct format for printing pointer values is "%p". However, keep in
    > mind that it's specifically for void* pointers. If you pass it a pointer
    > of some other type, in principle, the consequences could be just as bad
    > as when you used "%x". In practice, your chances of being unlucky enough
    > for it to work are significantly better, because systems where all
    > pointer types have compatible representations are pretty common. The
    > most common alternative is systems where the word size is larger than 1
    > byte. On such systems, a pointer to a specific byte must contain both
    > the address of the word containing that byte, and an offset within the
    > word for that particular bytes. Pointers to types that have alignment
    > requirements of 1 word or larger, on the other hand, can be represented
    > by a pointer that only identifies the first word of that object.
    > Therefore, on such systems, there's a decent chance that sizeof(void*)
    > != sizeof(long double*).


    That's slightly misleading. There are plenty of systems with 8-bit
    bytes and a "word size" of, say, 16, 32, or 64 bits. Most such systems
    use the same representation for all pointer types. The issue you're
    talking about occurs on *word-addressed* systems. (The obvious way to
    implement a C compiler on such a system is to set CHAR_BIT to the word
    size, but being able to communicate with systems with 8-bit bytes is
    often an overriding concern.)

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Working, but not speaking, for JetHead Development, Inc.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, May 28, 2013
    #2
    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. John Bode
    Replies:
    0
    Views:
    184
    John Bode
    May 28, 2013
  2. SG
    Replies:
    0
    Views:
    186
  3. Malcolm McLean

    Re: confused the address of struct member like this

    Malcolm McLean, May 28, 2013, in forum: C Programming
    Replies:
    0
    Views:
    186
    Malcolm McLean
    May 28, 2013
  4. Victor Bazarov
    Replies:
    0
    Views:
    179
    Victor Bazarov
    May 28, 2013
  5. Victor Bazarov
    Replies:
    3
    Views:
    174
    Jorgen Grahn
    May 29, 2013
Loading...

Share This Page