Question about -> dereferencing

This is a discussion on Question about -> dereferencing within the C Programming forums, part of the General Programming Boards category; Hi, Code: struct blah { int a; int b; }; struct blah *tmp = (struct blah *) 0; printf("%p\n", &tmp->b); ...

  1. #1
    Registered User
    Join Date
    Jun 2009
    Posts
    8

    Question about -> dereferencing

    Hi,

    Code:
    struct blah {
        int a;
        int b;
    };
    struct blah *tmp = (struct blah *) 0;
    printf("%p\n", &tmp->b);
    This is essentially the code to find the offset of member 'b' from the beginning of the struct 'blah'. The book I was reading said typecasting 0 into the struct 'blah' was fine as long as we didn't dereference it. I agree with that, but I see that the code uses the '->' operator in conjunction with the '&' to get the address. I was under the impression that 'tmp->b' is basically synonymous to '(*tmp).b'. Doesn't this imply that 'tmp' would first be dereferenced before the address is gotten? If so, shouldn't it be an out of bounds error? Or is it fine because the compiler optimises it somehow so that 'tmp' is never actually dereferenced? Any insight would be appreciated. Thanks in advance.

  2. #2
    and the hat of wrongness Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    32,442
    Which is why we use the offsetof() macro.
    offsetof - Wikipedia, the free encyclopedia
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.
    I support http://www.ukip.org/ as the first necessary step to a free Europe.

  3. #3
    Registered User
    Join Date
    Oct 2008
    Location
    TX
    Posts
    2,047
    For starters create an object of that type ie struct blah before you dive into getting the offset of any of its members.

  4. #4
    Captain Crash brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,235
    You can usually do this in practice, but it's not correct. You need to either create one of these structs for real, or use offsetof().

    Unless you're doing something really, really weird, though, I don't know why you'd need to know the offset of a particular member in a struct.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  5. #5
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,046
    At least one compiler I know of (Turbo C -- sigh) catches NULL dereferences and prints "NULL pointer dereference" instead of segfaulting.

    You're right, though -- my gcc (4.3) doesn't segfault and in fact works as "expected".
    Code:
    $ ./nooffset
    0x4
    $
    I'd guess that that's a compiler extension.

    If I look at the generated assembly, even with optimizations disabled, I see GCC moving a hard-coded '4' into a register. For what it's worth, at least one library seems to be using this extension to implement offsetof.
    Code:
    slang.h:2252:# define offsetof(T,F) ((unsigned int)((char *)&((T *)0L)->F - (char *)0L))
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  6. #6
    Captain Crash brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,235
    Quote Originally Posted by dwks View Post
    At least one compiler I know of (Turbo C -- sigh) catches NULL dereferences and prints "NULL pointer dereference" instead of segfaulting.
    That's absolutely critical on DOS. A far pointer which points to NULL, if written to, will destroy the first entry of the interrupt vector table -- the timer vector -- which is pretty much guaranteed to crash the whole system within 1/18.2th of a second

    I'd be very surprised if even Turbo C generated a fault with this bit of code, though. Nothing actually needs to be dereferenced, so no l-value or r-value needs to be generated by the compiler.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  7. #7
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by brewbuck View Post
    That's absolutely critical on DOS. A far pointer which points to NULL, if written to, will destroy the first entry of the interrupt vector table -- the timer vector -- which is pretty much guaranteed to crash the whole system within 1/18.2th of a second
    Actually, the first 8 entries in the interrupt vector table is taken by the exception vectors, the first one being division by zero.

    But certainly, any overwriting of the vector table is likely to lead to very bad things.

    Unfortunately, Turbo C only catches references to exactly NULL, not other invalid accesses that are a bit from NULL - such as perhaps the vectors for the timer interrupt.

    I'd be very surprised if even Turbo C generated a fault with this bit of code, though. Nothing actually needs to be dereferenced, so no l-value or r-value needs to be generated by the compiler.
    Sure, I do not think any compiler will actually dereference NULL to get the address.

    However, as pointed out, there is an offsetof macro defined in most compilers (is it part of the standard even, I can't remember). Certainly, creating a variable just to hold a zero-value is not ideal. If you must do these sort of things, do this:
    Code:
    #define myoffset(T, element) &(*T)(0)->element
    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  8. #8
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,046
    Code:
    $ man offsetof
    ...
    CONFORMING TO
           C89, C99, POSIX.1-2001.
    ...
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  9. #9
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    By the way, there is no way that the compiler should ever dereference the pointer if you use & on a ptr->x element. It will read the pointer value itself, and add the offset of x. There is no reason, and in fact in some situations (drivers with hardware registers) it would lead to incorrect behaviour to access ptr->x (say it's a fifo-register that changes when being read!)

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  10. #10
    Registered User
    Join Date
    Jun 2009
    Posts
    8
    Thanks guys. Yeah, as many of you have guess the code I presented is basically how the offsetof macro is defined sometimes. I was just trying to figure out how it worked. Thanks for all those that answered and thanks matsp especially, your last comment really cleared it up.

    By the way...does this mean that Turbo C does not comply with the c99 standards because it caught the null pointer dereference?

  11. #11
    C++まいる!Cをこわせ! Elysia's Avatar
    Join Date
    Oct 2007
    Posts
    22,428
    Turbo C doesn't comply with C99. Not sure if it really complies fully with C90 either.
    It's a very old compiler (hence should be avoided).
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. > > > Urgent Help < < <
    By CodeCypher in forum C Programming
    Replies: 2
    Last Post: 01-31-2006, 01:06 PM
  2. question about reading in strings from a file :>
    By bball887 in forum C Programming
    Replies: 8
    Last Post: 04-13-2004, 06:24 PM
  3. Question...
    By TechWins in forum A Brief History of Cprogramming.com
    Replies: 16
    Last Post: 07-28-2003, 09:47 PM
  4. Pointer Terminology Question
    By SourceCode in forum C Programming
    Replies: 2
    Last Post: 03-07-2003, 08:11 AM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21