结构体类型创建
1.有名结构体的定义方式
(1)声明结构体的同时,定义结构体
struct Stu //Stu为结构体名
{
char name[10];
char sex[5]; //结构体成员
short age;
}student1,student2; //student1,student2为结构体变量
(2)先声明,后定义
struct Stu //Stu为结构体名
{
char name[10];
char sex[5]; //结构体成员
short age;
};
struct Stu student1; //student1为结构体变量
2.无名结构体的定义方式
struct
{
char name[10];
char sex[5]; //结构体成员
short age;
}student1; //student1为结构体变量
3.别名结构体的定义方式
typedef struct Student //Student为结构体名
{
char name[10];
char sex[5]; //结构体成员
short age;
}Stu; //Stu为结构体类型的别名
Stu student1; //相当于struct Student student1
结构体初始化
1.定义的同时初始化
2.先定义再逐个初始化
struct Student//Student为结构体名
{
char name[10];
char sex[5]; //结构体成员
short age;
};
int main()
{
//1.定义的同时初始化
struct Student stu1 = {"小明","男",17};
//2.先定义再逐个初始化
struct Student stu2;
strcpy(stu2.name,"小红");
strcpy(stu2.sex,"女");
stu2.age = 16;
return 0;
}
结构体内存对齐
一个结构体所占内存大小并不等于其所有元素内存大小之和;
例:
struct S
{
char a;
int b;
double c;
};
int main()
{
struct S str;
printf("sizeof(char) = %d\n",sizeof(char));
printf("sizeof(int) = %d\n",sizeof(int));
printf("sizeof(double) = %d\n",sizeof(double));
printf("sizeof(str) = %d\n",sizeof(str));
return 0;
}
运行结果:
经过测试,结构体str的大小并不等于sizeof(char)+sizeof(int)+sizeof(double)=13,而结果为16,那结构体的内存是怎样计算的?
结构体内存的计算是需要遵循结构体内存对齐规则的,那为什么结构体需要内存对齐?
结构体内存对齐目的:
1.平台原因:
(1)不是所有的硬件平台都能访问任意地址上的任意数据的。
(2)某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2.性能原因:
(1)为了访问未对齐的内存,处理器需要做做两次内存访问,而对齐的内存只需要一次访问。
内存对齐的本质是:牺牲空间换取时间;
了解了内存对齐的原因,接下来需要学习内存对齐的规则;
1.第一个成员在与结构体变量偏移量为0的地址处;
例:
struct S
{
char a;
int b;
};
内存示意图:
a为结构体第一个变量,存放在偏移量为0的地址处;
2.其他成员要对齐到对齐数的整数倍地址处;
对齐数=编译器默认对齐数与该成员大小的较小值;
Linux环境下对齐数为4,windows环境下对齐数为8;
例:
在Windows环境下:
struct S
{
char a;
int b;
double c;
};
变量a(1字节)先存入偏移量为0(存放在第1字节处)的地址处,存放变量b时,变量b的大小为4字节,对齐数为4,则存放在第5~8字节处,同理变量c的大小为8字节,对齐数为8,则存放在第9~16字节处;
示意图:
3.结构体总大小为最大对齐数(每个成员变量除了第一个成员都有一个对齐数)的整数倍;
例:
struct S
{
char a;
double c;
int b;
};
在windows环境下:
由规则1,2计算出结构体总大小为8+8+4=20,而结构体的最大对齐数为8,20不是8的整数倍,所以将它补到8的整数倍,也就是24,最终得出结构体总大小为24;
示意图:
4.如果结构体1嵌套了结构体2,结构体2对齐到自己的对齐数的整数倍处,结构体1的大小就是其成员最大对齐数的整数倍;
规则4其实就将被嵌套的结构体看做普通变量,按规则1,2,3对齐即可;
位段,位段计算机大小
c语言允许在一个结构体中以位段为单位来指定其成员所占内存大小,这种以位为单位的成员称为位段,利用位段能够利用较少的位数存储数据;
位段的定义方式:
例:
int a:2;
int :0;
int b:1;//另一个存储单元
位段的规则:
在某些机器上, 位段总是作为 unsigned 处理, 而不管它们是否被说明成 unsigned 的;
大多数C 编译器都不支持超过一个字长的位段;
位段不可标明维数, 不能说明位段数组, 例如 flag:l[2];
位段不可以取地址;
枚举,联合
枚举
枚举是一个被命名的整型常数的集合,内部成员第一个默认值是0,后边依次+1;
例如enum A{
a,//默认值是0
b,//1
c,//2
d,//3
}
联合体
在联合体中,各成员共享一段内存空间, 一个联合变量的长度等于各成员中最长的长度。共享指该联合变量可被赋予任一成员值,但每次只能赋一种值, 赋入新值则改变旧值;
union str
{
int a;
char b;
double c;
};
联合体str中成员a,b,c共用一块内存;