请教(&((s_a *)0)->c)中的0是什么意思

请问(&((s_a *)0)->c)中的0是什么意思。
#include   <string.h>
#include   <stdio.h>
#include   <stdlib.h>

struct   A
{
      char     a;
      char*   b;
      char   c;
};

typedef   struct   A   s_a;

int   main()
{

        unsigned   long   d   =   (unsigned   long)(&((s_a   *)0)-> c);
        printf( "d   =   %d\n ",d);
}
结果是:d=8
我理解   结果是结构成员C的地址偏移量,但我不理解(&((s_a   *)0)-> c)中0的含义,而且当我把0改成如10,20的时候也可以运行,只是结果分别是18和28,所以请教高手解释一下   “&((s_a   *)0)-> c)”的含义。

------解决方案--------------------
0 是空指针。

成员地址 = 结构地址 + 偏移

当结构地址 为 0 时,成员地址 == 偏移
------解决方案--------------------
(s_a *)0,将常数0强制类型转换为结构A类型的指针。然后((s_a *)0)-> c,取这个结构指针的成员变量c。最后(unsigned long)(&((s_a *)0)-> c),返回这个结构指针的成员c的地址值,再将此地址值强制类型转换为unsigned long,所以就得到以0为基址,以c在结构A中的偏移地址之和8了。
理所当然,将0改为10、20得到的基址+偏移的结果就是18和28了。
------解决方案--------------------
偏移量理解对了。
前面的意思是,有一个内存地址,这个地址值 为0 ,
现在把他当成是一个指针了。这个指针指向了A类型的结构。
现在要得到的是这个结构成员a.c的地址。把这个地址当成长整型输出。

上边的意思,就是把如下的内存位置上的值,按照示意图来解释。 注意是解释!
示意图 ==================
0x00000000 //A的首地址在此! A.a也在此。
0x00000001 对齐的填充字节
0x00000002 对齐的填充字节
0x00000003 对齐的填充字节
0x00000004 //A.b指针的4个字节在此 1
0x00000005 2
0x00000006 4
0x00000007 3
0x00000008 //A.c 在此
0x00000009 对齐的填充字节
0x0000000a 对齐的填充字节
0x0000000b 对齐的填充字节