1

I came across a piece of code where NULL is typecast to an structure pointer type (foo *) 0,and with that pointer de-referencing a member ((foo *)0)->m) ,and using address of that &(((foo *)0)->m)) and type casting it to integer to get the memory index of that member with in the structure.((unsigned int)(&(((foo *)0)->m))).

I also see that this macro has specific behavior of giving the offset all the times by giving the index.Please try to help enlighten me.Thanks for the inputs.

#include <stdio.h>
#define  MACRO(m) ((unsigned int)(&(((foo *)0)->m)))

typedef struct
{
int a;
int b;
int c;
int d;
}foo;

int main(void) {
    printf("\n  %d  ", MACRO(c));
    return 0;
}
Klas Lindbäck
  • 33,105
  • 5
  • 57
  • 82
Adi
  • 729
  • 2
  • 6
  • 13
  • 1
    why do you ask exactly the same question again? – phuclv Sep 09 '16 at 11:23
  • 1
    @LưuVĩnhPhúc I guess because it's debatable whether the other question should have been closed. – nwellnhof Sep 09 '16 at 11:28
  • 2
    While I agree that the original question should not have been closed, the correct way would have been to try to reopen the other one, and not to re-ask it again. – alain Sep 09 '16 at 11:33
  • 1
    This *is* undefined behavior. You're just (un)lucky nothing bad happens in this specific case, on this specific compiler, with these specific settings. – EOF Sep 09 '16 at 11:47
  • @EOF A good answer to this question should detail just why it is UB and preferably suggest a compliant way to get the offset of a struct member. – Klas Lindbäck Sep 09 '16 at 11:54
  • or maybe answer the first version (the (suggested) duplicate). – Klas Lindbäck Sep 09 '16 at 11:56
  • 2
    Please do not post duplicates of your own question, especially since it has a perfectly good answer with a standard reference. – Sergey Kalinichenko Sep 09 '16 at 11:57

1 Answers1

1

(As explicitly stated in the comments, this answer is not technically correct. However, I retain this answer to give you an intuition of what is happening.)

Taking the address &x of any variable x does not actually evaluate x.

Specifically for pointer foo *p, &(*p) will not dereference p. In fact, &(*p) is equal to just p.

Your example is just a little bit more contrived, because it does not get the address of some *p (in your case, p = (foo *) 0), but of one of its members. However, the argumentation still holds: p->m is just a variable, and getting that address never evaluates the variable itself.

You may imagine that, "under the hood", the compiler only computes addresses until you actually access the data. And getting an address by &x never accesses that data.

Martin Nyolt
  • 4,463
  • 3
  • 28
  • 36
  • 1
    "`&(*p)` will never dereference `p`": any decent optimizing compiler certainly won't do it, but there is nothing that forbids the dereference in principle. – Blagovest Buyukliev Sep 09 '16 at 11:35
  • 4
    `&*p` is specified to be equal to `p` even if `p` is `NULL`, but `&p->m` is *not*. This *is* undefined. – EOF Sep 09 '16 at 11:48