1.结构体
1.结构体的声明
struct tag
{
member-list;
}variable-list;
2.结构体的特殊声明
struct
{
int a;
char b;
float c;
}x;
struct
{
int a;
char b;
float c;
}a[20], *p;
上述代码属于匿名结构体类型
1)编译器会把上面的生命当成完全不同的类型所以是非法的
2)匿名的结构体类型,只能使用一次,因为没有对结构体类型重命名
3.结构体的自引用方式
如果一个结构体内部包含同类型的结构体变量,结构体变量的大小就会无穷的大
所以正确的自引用方式是使用指指针:
struct Node
{
int data;
struct Node* next;
};
4.结构体的内存对齐
对齐规则:
1.结构体的第一个成员对齐到和结构体变量起始位置偏移量是0的地址处
2.其他成员变量对齐到对齐数的整数倍的地址处去
对齐数是编译器默认的一个对齐数与该成员变量大小的较小值
3.结构体总大小为最大的对齐数的整数倍
例:
struct S1
{
char c1;
int i;
char c2;
};
printf("%d\n", sizeof(struct S1));
c1从零偏移位置处开始占一个字节,接着往下看,i是int类型占4个字节,对齐数是4,所以i从偏移量为4的位置处存,c2对齐数是1,在i后面存,现在是九个字节,由于最大对齐数是4,根据规则4,结构体需要占12个字节空间才可以。
为什么要存在内存对齐:1)平台原因 2)性能原因
修改对齐数:
#progma pack(x)这个预处理指令,可以改变编译器的默认对齐数为x
取消默认对齐数,使用
#progma pack()
5.结构体位段
位段的声明与结构体类似:
1)位段的成员必须是int,unsigned int 或者signed int
2) 位段的成员名后必须有一个冒号和数字
3) 可移植程序避免使用位段
4) 位段的空间是按照4个字节或者1个字节的方式来开辟的
5) 位段可以节省空间
struct A
{
int _a:2;
int _b:5;
int _c:10;
int _d:30;
};
位段的注意事项:位段的几个成员共有一个字节,这样有些成员的起始位置并不是某个字节的起始位置,那么这些位置处是没有地址的,内存中每个字节分配一个地址,一个字节的内部的bit位是没有地址的
不能对位段成员使用&操作符,而应该是先输入放在一个变量中,然后赋值给位段的成员
2.联合
1.联合体类型的声明
联合体也是由一个或者多个成员构成,可以是不同类型。联合体的特点是所有成员共用一块空间。给一个成员赋值,其他成员的值也跟着变化。
2.联合体的特点
联合体的大小,至少是最大成员的大小
3.联合体大小的计算
联合的大小至少是最大成员的大小
当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。
4.联合体的一个练习(判断当前机器的大小端)
int check_sys()
{
union
{
int i;
char c;
}un;
un.i = 1;
return un.c;//返回1是⼩端,返回0是⼤端
}
3.枚举
1.枚举类型的声明
把可能的取值一一列举
enum Day//星期
{
Mon,
Tues,
Wed,
Thur,
Fri,
Sat,
Sun
};
2.枚举的优点
增加代码的可读性和可维护性
和#define定义的标识符比较枚举有类型检查,更加严谨
便于调试,预处理阶段会删除define定义的符号
枚举常量是遵循作用域规则的,枚举声明在函数内,只能在函数内使用
3.枚举类型的使用(在C语言中是可以拿整数给枚举变量赋值的)
enum Color//颜⾊
{
RED=1,
GREEN=2,
BLUE=4
};
enum Color clr = GREEN;
标签:字节,int,成员,位段,枚举,详解,&&,对齐
From: https://blog.csdn.net/m0_73425221/article/details/136892594