自定义类型小节,主要涉及到结构体,共用体,联合体中的
本节内容比较简单,最重要的就是计算内存对齐。
结构是一些值的集合,这些值叫做成员变量。结构的每个成员可以是不同类型的变量。
struct st{member-list;
}variable-list;//e.g.
struct student{char name[20];int age;char sex[5];char id[20];
}NAMEOFASTU;
特殊声明,不完全声明:
可以在定义结构体的时候省略掉结构体的标签。但是如果这样,相同的定义方法定义两个匿名结构体,编译器默认是不同的类型。不同类型的结构体不能进行 x = y等操作。
struct{int a;int b;char c;
}x;
结构体可以设定一个类型就是该结构体本身的成员变量 (指针)。
struct Node{int data;struct Node* next;
};
简写:每次都写struct Node非常麻烦,可以用如下方法:
typedef struct Node{int data;struct Node* next;
}Node;
本身定义了struct Node类型,而且还typedef了 struct Node 为 Node类型。之后在使用中就可以写成Node 了。
定义变量有两种方法:
在声明类型的同时就定义变量,如下面例子X所示
单独定义结构体变量Y
//方法1
struct A{int a; int b;
}X;
//方法2
struct A Y;
初始化变量:定义变量的同时赋值
struct A a = {10, 20};
同样的可以在声明结构体的时候进行初始化变量:
struct A{int a;int b;
}X = {10, 20};
可以嵌套初始化结构体:
struct A{int a;int b;
};
struct Node{int data;struct A a;struct Node* next;
}n1 = {10, {1, 2}, NULL};
//结构体嵌套初始化和声明
第一个成员在与结构体变量偏移量为0的地址处。(无偏移)
其他成员变量要对齐到对齐数的整数倍的地址处。
对齐数 = 编译器默认的对齐数 与 该成员大小的较小值。
VScode中默认的值为4/8.
结构体总大小为最大对齐数的整数倍(每个成员变量都有自己的对齐数)
如果嵌套了结构体,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数的整数倍(含嵌套结构体的对齐数)。
为什么存在内存对齐?
平台原因
性能原因:拿空间换取时间
如何设计结构体可以做到满足对齐的同时节省空间?
struct s1{char c1;int i;char c2;
};
struct s2{char c1;char c2;int i;
};
计算一下s1结构体的大小为: 4 + 4 + 4 = 12;
s2 : 4 + 4 = 8,因为c1和c2加起来不够4,后面2 + sizeof(int) > 4,所以两个char先对齐得4,加int的4,总共为8.
所以在声明结构体的时候,尽量让占空间小的放在一起,尽量节省空间。
修改默认对齐数:
#pragma pack();//恢复默认的对齐数 #pragma pack(8);//修改对齐数为8
所以在对齐方式不适合的时候,我们可以自己修改默认对齐数。
结构体传参,最好传递指针(地址),用指针去找到其中的成员变量,远比传递结构体本身方便得多。
与结构体类似,但是不同点在于:
位段的成员必须是int (unsigned int,或signed int), char类型(属于整型的类型)。(int型能不能表示负数视编译器而定,比如VC中int就默认是signed int,能够表示负数)。
位段的成员名后面有一个冒号和数字。
位段的定义格式为: type [var]:digits
位段名称var是可选参数,即可以省略。digits表示该位段所占的二进制位数。
如下:
struct A {int a : 2; // 位段a,占2bit位int b : 5; // 位段b,占5bit位int c : 7; // 位段c,占7bit位 };
总共占据14bit位,开辟一个int是4个字节,32bit位。14 < 32,所以开辟一个int大小的空间就可以。
上述代码用sizeof查看,发现占用4个字节大小。
对于位段结构,编译器会自动进行存储空间的优化,主要有这几条原则:
如果一个位段存储单元能够存储得下位段结构中的所有成员,那么位段结构中的所有成员只能放在一个位段存储单元中,不能放在两个位段存储单元中;如果一个位段存储单元不能容纳下位段结构中的所有成员,那么从剩余的位段从下一个位段存储单元开始存放。(在VS中位段存储单元的大小是4字节).
如果一个位段结构中只有一个占有0位的无名位段,则只占1或0字节的空间(C语言中是占0字节,而C++中占1字节);否则其他任何情况下,一个位段结构所占的空间至少是一个位段存储单元的大小;
enum Day{Mon,Tues,Wed,Thur,Fri,Sat,Sun
};
Enum 之后的是枚举类型,{ }中的内容是枚举常量,就是枚举类型的可能取值。这些枚举常量默认从0开始,依次递增。在定义的时候也可以赋初值。如下
enum Color{RED = 1,GREEN = 2,BLUE = 3
};
enum Color{RED = 1,GREEN = 2,BLUE = 3
};enum Color clr = GREEN; //只可以拿枚举常量给枚举变量赋值,不要用 enum Color clr = 5;
联合式特殊的自定义类型,包含一系列的成员,一大特征是这些成员共用同一块空间。所以联合体也叫共用体。
//声明
union Un{char c;int i;
};
//定义
union Un un;
成员共用一块内存空间,所以一个联合体变量的大小,至少是最大成员的大小,因为联合体至少有能力保存最大的成员。
自定义类型小节完。
下一篇:2.3 二分搜索技术