宏offsetof分析

1、前言

在C语言的结构体中,由于字节对齐的问题,所以成员的地址并不能直接根据数据类型的大小进行计算,使用宏offsetof可以获得结构体成员相对于结构体首地址的字节偏移量。

2、offsetof宏实现

在C标准库中offsetof的声明如下,需要包含头文件stddef.h:

size_t offsetof(type, member);

参数:

         type:结构体类型

         member:结构体中成员的名称

返回值:

         返回类型为size_t的值,表示type中member的偏移量

该宏在Linux内核源码内的实现如下:

#define offsetof(TYPE, MEMBER)   ((size_t)&((TYPE *)0)->MEMBER)

通过上面这个宏为什么能获取到结构体某个成员的偏移地址呢?首先,偏移地址的计算方法为:当前的成员地址-结构体首地址=偏移地址,在offsetof宏中,将0地址强制转换成了(TYPE *)类型,也就是说结构体的首地址为0,所以根据偏移地址计算方法,可以知道当前成员的地址也就等于偏移地址,所以宏offsetof将成员的地址取出并返回,获得的就是某个成员的偏移地址了,返回值为size_d,需要引起注意。

3、实例

下面是一个offsetof的使用实例,代码如下所示:

#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>

struct s {
    int i;
    char c;
    double d;
    char a[];
};

int main(int argc, char *argv[])
{
    printf("sizeof(struct s)=%zd\n", sizeof(struct s));
    printf("offsets: i=%zd; c=%zd; d=%zd; a=%zd.\n",
            offsetof(struct s, i), offsetof(struct s, c),
            offsetof(struct s, d), offsetof(struct s, a));
    
    exit(EXIT_SUCCESS);
}

使用gcc编译后运行结果如下所示:

由于字节对齐的原因,所以结构体s的大小为16个字节,假设结构体首地址从0开始,由于int类型占用4字节,所以地址0到3为变量i所用,char类型占用1字节,地址4为变量c所用,由于需要字节对齐并且double类型的开始地址必须是8的整数倍,因此地址5到7被填充,double类型占用8字节,地址8到15被变量d所用,a的地址则从地址16开始,因此,通过宏offsetof便可以得到结构体成员的偏移地址。

猜你喜欢

转载自www.cnblogs.com/Cqlismy/p/11428859.html