JaronZou 2022-04-28 17:03 采纳率: 100%
浏览 51
已结题

空指针(NULL)的用法问题

问题的背景

这两天在研究字节对齐的问题,偶然看到了博客园某位答主的代码:

/* OFFSET宏定义可取得指定结构体某成员在结构体内部的偏移 */
#define OFFSET(st, field)     (size_t)&(((st*)0)->field)
typedef struct{
    char  a;
    short b;
    char  c;
    int   d;
    char  e[3];
}T_Test;

int main(void){
    printf("a-%d, b-%d, c-%d, d-%d\n", 
            OFFSET(T_Test, a), 
            OFFSET(T_Test, b), 
            OFFSET(T_Test, c), 
            OFFSET(T_Test, d));
    printf("a-%d\n", (size_t)&(((T_Test*)0)->a));
    return 0;
}

这段代码的用途是查看结构中每个字段的偏移地址,程序的输出如下:

a-0, b-2, c-4, d-8
a-0

问题

我的问题是

#define OFFSET(st, field)     (size_t)&(((st*)0)->field)

这个宏定义中的 (size_t)&(((st*)0)->field) 是如何起作用的,((st*)0) 不是一个 st* 类型的空指针吗,为什么能够通过它访问 T_Test 中的字段。

  • 写回答

2条回答 默认 最新

  • @魏大大 JavaScript领域新星创作者 2022-04-28 17:12
    关注
    tyoedef struct{ int a; char b; }Msg; 结构体Msg,如果将一个整数0强转成Msg可以理解为,Msg所在的首地址为0,那么((Msg *)0)->b,就可以理解为取结构体成员b的内容,但是我们自己知道其实0这个首地址并没有存储结构体Msg的信息,取内容也就毫无意义,所以我们不要取内容。我们看看对这个成员取地址(引用)会有什么事情发生,&(((Msg *)0)->b)就相当于结构体Msg的成员b的首地址。我们也可以换一种思维理解,其实&(((Msg *)0)->b)就是b相对于结构体首地址的偏移量,因为结构体首地址为0,偏移后的地址减去首地址就是偏移量,偏移后的地址-0=偏移量,那么偏移量就等于偏移后的地址,那么如果在对结构体成员做偏移处理的时候看着就非常清晰,而且后期维护添加成员使用这个方法源码不用做任何改动,因为无论增加多少成员偏移量都是动态的并不是用常量写死的. 希望对你有用
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

问题事件

  • 系统已结题 5月6日
  • 已采纳回答 4月28日
  • 创建了问题 4月28日

悬赏问题

  • ¥15 想问一下树莓派接上显示屏后出现如图所示画面,是什么问题导致的
  • ¥100 嵌入式系统基于PIC16F882和热敏电阻的数字温度计
  • ¥15 cmd cl 0x000007b
  • ¥20 BAPI_PR_CHANGE how to add account assignment information for service line
  • ¥500 火焰左右视图、视差(基于双目相机)
  • ¥100 set_link_state
  • ¥15 虚幻5 UE美术毛发渲染
  • ¥15 CVRP 图论 物流运输优化
  • ¥15 Tableau online 嵌入ppt失败
  • ¥100 支付宝网页转账系统不识别账号