1
#include<stdio.h>
main()
{
        unsigned char c;
        typedef struct name {
                long  a;
                int b;
                long c;
        }r;
        r re = {3,4,5};
        r *na = &re;
        printf("%d", *(int*) ((char*)na + (unsigned int) & ( (struct name *)0 )->b));
}

OUTPUT :

4

I would be thankful if somebody explain in detail what printf statement is doing in this c program ? According to me int is casted . then char pointer is casted to na. But I cannot understand what whole statement overall doing ? What casting doing here ? b is not pointer but it seems it is used as pointer. I have found this problem one of the c programming book.It seems be it calculate structure offset but I still not able to know how. Please help me to understand program in detail.

Punit Vara
  • 3,744
  • 1
  • 16
  • 30

1 Answers1

3

The code &((struct name *)0)->b is indeed known as the "offsetof" operation and is in fact a well-known C macro.

The idea is that if a is a structure of type A then &a.b is equal to the address of a plus the offset of b in a. Since here NULL is used instead of the address of a, the result is just the offset of b in structures of type A.

According to Wikipedia,

This works by casting a null pointer into a pointer to structure st, and then obtaining the address of member m within said structure. While this implementation works correctly in many compilers, it has undefined behavior according to the C standard,2 since it involves a dereference of a null pointer (although, one might argue that no dereferencing takes place, because the whole expression is calculated at compile time)

So let's look at the expression in printf step-by-step.

The expression (unsigned int) & ( (struct name *)0 )->b)) calculates offset of b in struct name as described above and casts the result to an integer. The result should be equal to sizeof(long) on most platforms.

The (char*)na in the code casts na, which is a pointer to struct name to a char pointer. This is required because sizeof(char) can be assumed to be 1 while sizeof(*na) is larger than 1. What we want to do is to use the address of *na as a raw numerical address instead of doing pointer arithmetic, so that if for example na==0x1234, then the result of ((char*)na + 4) is equal to 0x1234 + 4 = 0x1238.

The sum results in a memory address. That address is equal to the address of member variable b in the object na, and is of type char *. Knowing that, the last step is to cast the address back to int * (because the type of b is int) and then to dereference the result (once again, we know that it points to b). The final outcome is the value of b, which is then printed.

Community
  • 1
  • 1
kfx
  • 8,136
  • 3
  • 28
  • 52
  • My actual question is to understand that printf statement dear. Still I am upvoting your answer as you tried – Punit Vara Jan 05 '16 at 19:23
  • @PunitVara: which parts are you still missing? I can expand on the answer. Once you understand the offsetof stuff, the rest is plain pointer arithmetic. – kfx Jan 05 '16 at 19:26
  • I am really thankful to you if you expand step by step that statement. – Punit Vara Jan 05 '16 at 19:29
  • 2
    Good breakdown of the pointer arithmetic. Basically, it's a convoluted way of saying `printf("%d", na->b);` – dbush Jan 05 '16 at 19:46
  • Thanks @dbush Why ending with unsigned int what is purpose of that one? – Punit Vara Jan 05 '16 at 19:51
  • The `unsigned int` cast treats the offset address as a number instead of a pointer. The updated answer describes it pretty well. – dbush Jan 05 '16 at 19:54