百度百科中,这样描述"结构体":“结构体是C语言中一种重要的数据类型,该数据类型由一组称为成员(或称为域,或称为元素)的不同数据组成,其中每个成员可以具有不同的类型。结构体通常用来表示类型不同但是又相关的若干数据。结构体类型不是由系统定义好的,而是需要程序设计者自己定义的。C语言提供了关键字Struct来标识所定义的结构体类型。”
在实际的工程项目中,结构体可以说无处不在,不管在哪种软件框架设计中,都会有它的身影。尤其在模块化的软件设计中,常常需要使用Struct结构描述要抽象的对象
举例:描述一个学生的信息元素如图
/* 用一个结构体描述学生各科成绩 */
struct Score_detail
{
float math_score;
float chinese_score;
float english_score;
float chemistry_score;
float physical_score;
float geography_score;
};
/* 用一个结构体描述学生 */
struct Student
{
char name[20]; //姓名
uint32 id; //学号
uint32 age; //年龄
uint16 score; //总成绩
struct Score_detail subject_score; //各科成绩
char sex; //性别
};
如果定义一个struct Student类型的变量AoTeMan
元素实际仅需要57 Byte空间,由于数据对齐(Align = 4 Byte),变量AoTeMan实际消耗了60 Byte字节空间。
计算结构体原理可参考:内存对齐三原则简洁懂,终极计算小技巧-CSDN博客
结构体元素id相对起始地址的偏移量为20,最直接的计算方法:
idOffset = (uint32)(&AoTeMan.id) - (uint32)(&AoTeMan);
那么有没有更方便的计算方法呢
- 采用宏定义方法
/* 定义一个宏,计算各成员相对于结构体起始地址的偏移量 */
#define offsetof(type,member) ((int) &((type *)0)->member)
如上的宏如何理解?
- ((type*)0):转换成type类型的结构体指针,且起始地址为0;
- (((type*)0)->member):引用结构体member成员;
- &(((type*)0)->member):取成员member地址;
- ((int)&(((type*)0)->member)):将获取的地址强制转换成int类型。
2.采用函数方法
为了得到确切的偏移量,可以使用offsetof
宏,它定义在<stddef.h>
头文件中:
#include <stddef.h>
// ... 其他代码 ...
printf("Offset of sex in Student: %zu\n", offsetof(struct Student, sex));
运行上面的代码会给sex
成员在Student
结构体中的确切偏移量。